ASP.NET Web API中的PUT路由

4

我正在尝试为Web API设置路由,认为这是非常简单的事情。然而,Web API中的路由在不同的HTTP动词上似乎并不一致。假设我有一个具有以下操作的控制器...

public class AvalancheController : ApiControllerBase
{

    // GET api/avalanche
    public IEnumerable<Avalanche> Get() {}

    // GET api/avalanche/5
    public Avalanche Get(int id) {}

    // GET api/avalanche/ActionTest/5
    [ActionName("ActionTest")]
    public Avalanche GetActionTest(int id) {}

    // GET api/avalanche/ActionTest/2
    [ActionName("ActionTest2")]
    public Avalanche GetActionTest2(int id) {}

    // POST api/avalanche
    public void Post([FromBody]Avalanche value) {}

    // PUT api/avalanche/5
    public void Put(int id, [FromBody]Avalanche value) {}

    // PUT api/avalanche/test/5
    [ActionName("Test")]
    public void PutTest(int id, [FromBody]Avalanche value) {}

    // DELETE api/avalanche/5
    public void Delete(int id) {}
}

我有以下定义的路由...

    config.Routes.MapHttpRoute(
        name: "ActionRoutes",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional },
        constraints: new
            {
                controller = "Avalanche",
                action = "(ActionTest|ActionTest2|Test)"
            }
    );


    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

然后,我得到了以下定义路由的结果...
GET api/Avalanche/ActionTest/{id}
GET api/Avalanche/ActionTest2/{id}
PUT api/Avalanche/Test/{id}
GET api/Avalanche   
POST api/Avalanche  
DELETE api/Avalanche/{id}

为什么默认的PUT路由没有被选中?默认GET和PUT之间的路由有什么不同?我尝试了各种方式来装饰函数,但结果都一样。主要想知道如何选择默认的PUT路由。如果您有任何建议可以修改这些路由,使得我不必为每个控制器指定动作名称的路由,那就太棒了。谢谢!Ian。编辑:我今天早上注意到以下路由也没有被定义...
GET api/Avalanche/{id}

https://dev59.com/IGkw5IYBdhLWcg3wfKrZ#14465655 - Ali
1个回答

1
很高兴您已经找到了解决问题的方法。但基于我对REST服务的学习,我想提供一些反馈意见。REST webservice的理念是将每个URL解析为资源(或实体),并根据HttpVerb确定操作。在这种情况下,您有三个GET操作,通过您的修改可以正常工作。
但我认为控制器也可以重新排列,只有一个GET操作,并且具有单一职责,从而更易于维护。例如:
AvalancheController
public class AvalancheController : ApiControllerBase
{
    public IEnumerable<Avalanche> GET()
    {

    }

    public void POST(Avalanche avalanche)
    {

    }
}

可以假设处理所有顶级雪崩,下面是需要定义的操作。
GET:返回所有雪崩
POST:插入新的雪崩
PUT:未使用
DELETE:未使用
AvalancheDetailsController
public class AvalancheDetailsController : ApiControllerBase
{
    public Avalanche GET(int id)
    {

    } 


    public int PUT(int id)
    {

    }

    public int DELETE(int id)
    {

    }
}

假设我们要处理单个雪崩,下面是需要定义的操作。

GET:返回单个雪崩
POST:未使用
PUT:更新单个雪崩
DELETE:删除单个雪崩

现在我假设我们已经清楚了控制器之间的区别。在您提到的操作中,可能会有不同的GET操作,但它仅返回单个 Avalanche。因此,我将更改GET方法以接受对象作为输入并检查值,即:

public class AvalanceRequest
{
  public int? Id {get;set;}
  public string Name {get;set;}
}


   public class AvalancheDetailsController : ApiControllerBase
    {
        public Avalanche GET(AvalanceRequest request)
        {
           //write business logic based on parameters
           if(request.Id.HasValue)
           //return avalanche;
           if(request.Name.IsNullOrEmpty())
           //return avalanche
        } 
        //other methods
  }

处理URL时,我并没有真正使用WebAPI,而是尝试使用ServiceStack开发REST服务。它允许将URL附加到控制器名称之外。 URL
api/Avalanche --> AvalancheController(根据HttpVerb调用操作)
api/Avalanche/Id --> AvalancheDetailsController(根据HttpVerb调用操作)
我不知道在WebAPI中是否可以以类似的方式附加URL,否则您最终将拥有默认配置并通过api/Avalanche和api/AvalancheDetails/id进行调用。
 config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

我很抱歉发了这么长的帖子,希望内容有意义。


有趣的方法。我需要更深入地思考一下。这是我的第一个REST API,所以我肯定对所有想法都持开放态度。我一直遵循的想法是容器将描述正在操作的主要数据类型,并使用操作来描述更复杂的操作。例如,如果您需要返回Avalanche项目数组的更复杂查找,例如GetAvalancheCreatedWithinDateRange(),那该怎么办?很快,每个动词一个函数的想法就会崩溃。 - Ian Lee
@IanLee,我也还在学习。是的,在实现之前最好先考虑一下。对于你的问题,由于它是IEnumerable<Avalanche>上的过滤器,我会在GET方法中使用具有date1和date2作为参数的自定义对象。但正如你所说,可能会出现这样的复杂情况,我遇到了这篇文章,它解释了这样的实现http://www.codeproject.com/Articles/21258/Everything-about-REST-web-services-what-and-how-Pa - Sunny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接