ASP.NET Web API中的多种PUT方法 [英] Multiple PUT methods in ASP.NET Web API

查看:39
本文介绍了ASP.NET Web API中的多种PUT方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个控制器 Groups ,它具有以下操作:

 公共GroupModel Get(整数ID)公共GroupModel帖子(CreateGroupModel模型)公共无效Put(PublicUpdateGroupModel模型)公共无效PutAddContacts(UpdateContactsModel模型)公共无效PutRemoveContacts(UpdateContactsModel模型)public void Delete(int ID) 

我想做的是使用标准的REST路由来调用标准的get,post,put,deleted方法.但是,如果将操作名称附加到URL,请调用 PutAddContacts PutRemoveContacts ,例如:

获取组/-调用获取方法

POST组/-调用Post方法

PUT组/-调用Put方法

删除组/-调用删除方法

PUT组/addcontacts-调用PutAddContacts方法

PUT组/删除联系人-调用PutRemoveContacts方法

是否可以设置路由来执行此操作,或者如果我想在URL中使用操作名称,是否需要沿着RPC路由进行路由?

解决方案

您现在拥有的东西
要使用上述方法,您需要进行RPC.那是因为您的示例已经将RPC风格做了一半.默认的WebAPI路由鼓励使用RESTful设置,但是,如果对路由进行了较小的更改,一切都会开始起作用.例如,您可以将默认路由更改为类似于典型的MVC路由:

  routes.MapRoute(name:"Default",url:"{controller}/{action}/{id}",默认值:new {controller ="Home",动作=索引",id = UrlParameter.Optional}); 

添加路由后,以典型的MVC方式调用事物,在其中使用控制器名称&行动.但是,从您的问题来看,我怀疑您实际上是想成为RESTful的,而不是只是想让它正常工作,所以请继续阅读...

保持REST状态
REST 不需要HTTP ,经常将两者一起讨论.REST实际上涉及具有语义精确表示形式的每个资源.使用HTTP时,这意味着尊重HTTP语义的唯一URI.因此,例如,使用HTTP GET进行的调用绝不应修改数据,因为这违反了HTTP对GET的定义以及混淆的HTTP基础结构(例如缓存).

POST/PUT与MERGE/PATCH
我们都熟悉GET,POST,PUT,HEAD等作为HTTP方法.通常,GET用于检索,POST用于添加,PUT用于修改(尽管有很多争论).但是,您有两种类型的修改:添加项目和从集合中删除项目.那么,这些都是PUT还是其他?社区尚未完全解决为此.

  • 选项1:自定义媒体类型-HTTP规范确实允许使用各种排序方法,实际上是浏览器将我们限制在了熟悉的子集上.因此,您可以创建 MERGE(Roy Fielding解决方法)或PATCH(一种oData解决方法)方法并定义这种新媒体类型的行为-可能是一种添加媒体,一种是删除媒体.

  • 选项2:使用POST/PUT -使用PUT来添加和删除联系人.只需将ID列表视为一个切换(如果存在,则删除,如果缺少添加),或者alternatley包含足够的信息以知道该怎么做.然后返回HTTP 303,指示客户端具有陈旧状态并刷新.

  • 选项3:完整列表-如果您的集合大小合理,则每次要更新时,您始终可以传递完整的联系人列表.这样,逻辑就是超级简单的擦除和替换.

从RESTful角度来看,真正重要的是,您的应用程序在所有方法中的行为均保持一致.因此,如果MERGE表示添加,则应始终表示添加.如果您希望将完整的ID传递给PUT,则始终传递完整的ID.

控制器设计
如果是我,我会将您的控制器分为多个控制器.一个控制人与组打交道,另一个控制人(作为一个组)交往,而第三个控制人与组中的一个联系人进行交易.像...

 //api/Group/公共列表< GroupModel>得到()公共GroupModel Get(int ID)public GroupModel Post(GroupModel model)//添加一个组public GroupModel Put(GroupModel model)//更新组(请参见上面的注释)public void Delete(int ID)//api/GroupContacts/public ContactsModel Get()//获取完整列表public void PostContacts(ContactsModel model)//推动一个完整的新状态public void Delete()//删除整个联系人组//api/GroupContact/354/public ContactModel Get(int id)//获取联系人ID#354public void PostContact(ContactModel model)//添加联系人(如果退出则覆盖)public void Delete(int id)//删除联系人(如果存在) 

如果您希望URL显示为嵌套(例如:/api/Group/Contacts /api/Group/Contact ),则可以查看我写的另一篇文章.恕我直言,asp.net的路由需要调整以支持嵌套更容易...但这是一个不同的问题;-)

I have a controller Groups with the following actions:

public GroupModel Get(int ID)

public GroupModel Post(CreateGroupModel model)

public void Put(PublicUpdateGroupModel model)

public void PutAddContacts(UpdateContactsModel model)

public void PutRemoveContacts(UpdateContactsModel model)

public void Delete(int ID)

And what I would like to do is use standard REST routing to call the standard get, post, put, delete mehods. But call the PutAddContacts and PutRemoveContacts if the action names are appended to the url, for example:

GET groups/ - calls Get method

POST groups/ - calls Post method

PUT groups/ - calls Put method

DELETE groups/ - calls Delete method

PUT groups/addcontacts - calls PutAddContacts method

PUT groups/removecontacts - calls PutRemoveContacts method

Is it possible to set up routing to do this or do I need to go down the RPC route for routing if I want to use action names in my URL's?

解决方案

What you have now
To utilize your methods as above you'll need to go RPC. That is because your example is already half way steeped in the RPC style of doing things. Default WebAPI routes encourage RESTful setups, but if you made a minor alteration to your routes everything would start working. For example you could change your default route to something like a typical MVC route:

routes.MapRoute( name    : "Default",       
                 url     : "{controller}/{action}/{id}",
                 defaults: new { controller = "Home", 
                                 action     = "Index", 
                                 id         = UrlParameter.Optional });

After adding the route, call things in typical MVC fashion where you use the controller name & action. From your question, however, I suspect you actually want to be RESTful, instead of just getting it to work so read on...

Being RESTful
REST doesn't require HTTP, although the two are often discussed together. REST is really about every resource having a semantically accurate representation. When using HTTP that means unique URI's that respect HTTP semantics. So for example, a call using HTTP GET should never modify data because that violates HTTP's definition of GET and confused HTTP infrastructure like caches.

POST/PUT vs MERGE/PATCH
We're all familiar with GET, POST, PUT, HEAD, etc.. as HTTP methods. Generally, GET is for retrieving, POST is for adding, and PUT is for modifying (although subject to lots of debate). Yet, you have two types of modifications: adding items and removing items from a collection. So are those both PUT or something else? The community hasn't quite settled on how to do this.

  • Option 1: Custom media type - The HTTP spec really allows for all sorts methods, it's the browsers that really restrict us to the familiar subset. So you can create MERGE (a Roy Fielding work around) or PATCH (an oData work around) methods and define the behavior for this new media type -- maybe one for adding and one for removing.

  • Option 2: Use POST/PUT - Use PUT for both adding and removing contacts. Just treat the list of ID's like a toggle (if exists remove, if missing add) or alternatley include enough information to know what to do. Then return an HTTP 303 indicating to the client it has a stale state and refresh.

  • Option 3: Full List - If your set is a reasonable size, you can always pass a complete list of contacts every time you want to update. This way the logic is a super simple wipe and replace.

What really matters from a RESTful perspective is that your application behaves in a consistent way across all methods. So if MERGE means add, it should always mean add. If you expect a complete set of ID's passed to PUT then always pass a complete set.

Controller Design
If it were me, I would break your controller into multiple controllers. One controller deals with Groups another deals Contacts (as a group) and a third deals with one contact within a group. Something like ...

//api/Group/
public List<GroupModel> Get()
public GroupModel Get(int ID)
public GroupModel Post(GroupModel model)  //add a group
public GroupModel Put(GroupModel model)   //update a group (see comments above)
public void Delete(int ID)


//api/GroupContacts/
public ContactsModel Get()                    //gets complete list
public void PostContacts(ContactsModel model) //pushes a COMPLETE new state
public void Delete()                          //delete entire group of contacts


//api/GroupContact/354/
public ContactModel Get(int id)             //get contact id #354
public void PostContact(ContactModel model) //add contact (overwrite if exits)
public void Delete(int id)                  //delete contact if exists

If you want your URL's to appear nested (eg: /api/Group/Contacts, /api/Group/Contact), you can look at this other post I wrote. IMHO, asp.net's routing needs a tune up to support nesting a bit easier ...but that's a different issue;-)

这篇关于ASP.NET Web API中的多种PUT方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆