繁体   English   中英

ASP.NET Web API中的多个PUT方法

[英]Multiple PUT methods in ASP.NET Web API

我有一个控制器Groups其中包含以下操作:

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)

我想做的是使用标准的REST路由来调用标准的get,post,put,delete mehods。 但是如果动作名称被附加到url,则调用PutAddContactsPutRemoveContacts ,例如:

获取组/ - 调用Get方法

POST组/ - 调用Post方法

PUT组/ - 调用Put方法

DELETE groups / - 调用Delete方法

PUT groups / addcontacts - 调用PutAddContacts方法

PUT groups / removecontacts - 调用PutRemoveContacts方法

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

你现在有什么
要使用上述方法,您需要使用RPC。 这是因为你的例子已经完成了RPC的做事方式。 默认的WebAPI路由鼓励RESTful设置,但如果您对路由进行了微小的更改,一切都将开始工作。 例如,您可以将默认路由更改为典型的MVC路由:

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

添加路由后,以典型的MVC方式调用您使用控制器名称和操作的内容。 但是,从你的问题来看,我怀疑你确实想要成为RESTful,而不仅仅是让它工作所以请继续阅读......

保持沉默
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 work around)方法,并定义此新媒体类型的行为 - 可能是一个用于添加,另一个用于删除。

  • 选项2:使用POST / PUT - 使用PUT添加和删除联系人。 只需将ID列表视为切换(如果存在则删除,如果缺少添加)或者altatley包含足够的信息以了解要执行的操作。 然后返回HTTP 303,指示客户端它具有陈旧状态并刷新。

  • 选项3:完整列表 - 如果您的设置大小合理,则每次要更新时都可以传递完整的联系人列表。 这种逻辑是一种超级简单的擦除和替换。

从RESTful角度来看,真正重要的是您的应用程序在所有方法中以一致的方式运行。 因此,如果MERGE意味着添加,它应该始终意味着添加。 如果您希望将一组完整的ID传递给PUT,那么总是传递一套完整的ID。

控制器设计
如果是我,我会把你的控制器分成多个控制器。 一个控制器处理组另一个交易联系人(作为一个组),第三个处理一个组内的一个联系人。 就像是 ...

//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

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

为了回应EBarr所说的,在Web API中进行分层路由可能会有点痛苦。 我在我的服务中经常使用它,所以我为Web API构建了替换路由服务。 Nuget在这里 ,源代码在GitHub上

这种路由方法要求您将URI命名空间构建为路径段的层次结构。 您可以将控制器附加到路径段树中的任意点,而不是将完整的URI模式与控制器匹配。

只是为了让您了解它的外观我创建了一个类似于您尝试的URI的小型自主样本:

internal class Program
{
   private static void Main(string[] args)
   {
    var baseAddress = new Uri("http://oak:8700/");

    var configuration = new HttpSelfHostConfiguration(baseAddress);
    var router = new ApiRouter("api", baseAddress);

    // /api/Contacts
    router.Add("Contacts", rcs => rcs.To<ContactsController>());

    // /api/Contact/{contactid}
    router.Add("Contact", rc =>
                          rc.Add("{contactid}", rci => rci.To<ContactController>()));

    // /api/Group/{groupid}
    // /api/Group/{groupid}/Contacts
    router.Add("Group", rg =>
                        rg.Add("{groupid}", rgi => rgi.To<GroupController>() 
                                                       .Add("Contacts", rgc => rgc.To<GroupContactsController>())));


    configuration.MessageHandlers.Add(router);

    var host = new HttpSelfHostServer(configuration);
    host.OpenAsync().Wait();

    Console.WriteLine("Host open.  Hit enter to exit...");

    Console.Read();

    host.CloseAsync().Wait();
  }
}

public class GroupController : TestController { }
public class ContactsController : TestController { }
public class ContactController : TestController { }
public class GroupContactsController : TestController { }


public class TestController : ApiController
{
    public HttpResponseMessage Get()
    {
        var pathRouteData = (PathRouteData) Request.GetRouteData();

        var paramvalues = new StringBuilder();

        foreach (KeyValuePair<string, object> keyValuePair in pathRouteData.Values)
        {
            paramvalues.Append(keyValuePair.Key);
            paramvalues.Append(" = ");
            paramvalues.Append(keyValuePair.Value);
            paramvalues.Append(Environment.NewLine);
        }

        var url = pathRouteData.RootRouter.GetUrlForController(this.GetType());

        return new HttpResponseMessage()
                   {
                       Content = new StringContent("Response from " + this.GetType().Name + Environment.NewLine
                                                   + "Url: " + url.AbsoluteUri
                                                   + "Parameters: " + Environment.NewLine
                                                   + paramvalues.ToString())
                   };
    }
}

您应该能够将此代码粘贴到控制台应用程序中,并添加对Microsoft.AspNet.WebApi.SelfHost和Tavis.WebApiRouter nugets的引用并进行试用。 如果您对这种路由可以走多远感到好奇,那么这里有一个更复杂的示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM