同一个 HttpVerb 的多个操作

Posted

技术标签:

【中文标题】同一个 HttpVerb 的多个操作【英文标题】:Multiple actions for the same HttpVerb 【发布时间】:2012-10-29 01:51:16 【问题描述】:

我有一个具有以下操作的 Web API 控制器:

    [HttpPut]
    public string Put(int id, JObject data)

    [HttpPut, ActionName("Lock")]
    public bool Lock(int id)

    [HttpPut, ActionName("Unlock")]
    public bool Unlock(int id)

并映射了以下路线:

        routes.MapHttpRoute(
            name: "Api",
            routeTemplate: "api/controller/id",
            defaults: new  id = RouteParameter.Optional 
        );
        routes.MapHttpRoute(
            name: "ApiAction",
            routeTemplate: "api/controller/action/id"
        );

当我提出以下请求时,一切都会按预期进行:

PUT /api/items/Lock/5
PUT /api/items/Unlock/5

但是当我尝试向以下方面提出请求时:

PUT /api/items/5

我得到以下异常:

Multiple actions were found that match the request:
    Put(int id, JObject data)
    Lock(int id)
    Unlock(int id)

我尝试将空操作名称添加到默认路由,但没有帮助:

[HttpPut, ActionName("")]
public string Put(int id, JObject data)

有什么想法可以将默认 RESTful 路由与自定义操作名称结合起来吗?

编辑:路由机制不会因控制器的选择而混淆。它对在单个控制器上选择 action 感到困惑。我需要的是在未指定任何操作时匹配默认操作。希望能澄清一些事情。

【问题讨论】:

看起来这可能会回答你的问题:***.com/questions/9499794/… @GiscardBiamby 感谢您提供的链接,我查看并尝试一下。 @GiscardBiamby 你肯定给我指出了正确的方向。这个答案:***.com/a/12185249/99373 帮助我弄清楚了我需要做什么并且它奏效了!如果您想要信用,请发布答案,我会接受。 【参考方案1】:

这是来自默认操作选择器ApiControllerActionSelector 的预期错误。您基本上拥有三个对应于 HTTP Put 动词的操作方法。还要记住,默认动作选择器考虑简单动作参数类型,它们都是原始 .NET 类型,众所周知的简单类型(System.StringSystem.DateTimeSystem.DecimalSystem.GuidSystem.DateTimeOffset,@987654331 @) 和底层简单类型(例如:Nullable<System.Int32>)。

作为您的问题的解决方案,我将为以下控制器创建两个控制器:

public class FooController : ApiController  

    public string Put(int id, JObject data)


public class FooRPCController : ApiController  

    [HttpPut]
    public bool Lock(int id)

    [HttpPut]
    public bool Unlock(int id)

路线如下所示:

routes.MapHttpRoute(
    name: "ApiAction",
    routeTemplate: "api/Foo/action/id",
    defaults: new  controller = "FooRPC" 
);

routes.MapHttpRoute(
    name: "Api",
    routeTemplate: "api/Foo/id",
    defaults: new  id = RouteParameter.Optional, controller = "Foo" 
);

另一方面(与您的主题不完全相关),我有三篇关于动作选择的博文,尤其是复杂类型参数。我鼓励您查看它们,因为它们可能会为您提供更多视角:

Complex Type Action Parameters and Controller Action Selection with ASP.NET Web API Complex Type Action Parameters with ComplexTypeAwareActionSelector in ASP.NET Web API - Part 1 Complex Type Action Parameters with ComplexTypeAwareActionSelector in ASP.NET Web API - Part 2

【讨论】:

出于好奇,这是“不能那样做”的案例吗?我真的更喜欢将东西保存在同一个控制器中,因为它使我的应用程序更易于维护。应用程序中还有许多其他控制器需要修改以支持此提议的实现。 @adaptive 查看我更新的答案。如果您设法让操作选择器满意,请确保您可以在一个控制器中处理它们。 感谢您富有洞察力的回答。所以也许我可以写一个自定义的ActionSelector 来解决这个问题? @adaptive 再次查看更新。我添加了一些博客文章链接。他们也可能有所帮助。恕我直言,您应该进行任何 RPC,但这只是我的意见。从头开始编写动作选择器很痛苦(我去过那里),并且默认的动作选择器没有那么可扩展。 感谢您提供的重要信息。我还需要一段时间才能报告回来。非常感谢!【参考方案2】:

在Giscard Biamby 的帮助下,我找到了this answer,它为我指明了正确的方向。最终,为了解决这个特定问题,我这样做了:

routes.MapHttpRoute(
    name: "ApiPut", 
    routeTemplate: "api/controller/id",
    defaults: new  action = "Put" , 
    constraints: new  httpMethod = new HttpMethodConstraint("Put") 
);

感谢@GiscardBiamby

【讨论】:

【参考方案3】:

首先,删除[HttpPut, ActionName("")],然后修改你的路由到这个

config.Routes.MapHttpRoute(
    name: "Api",
    routeTemplate: "api/controller/id",
    defaults: new  id = RouteParameter.Optional ,
    constraints: new  id = @"^[0-9]+$" 
    );  

【讨论】:

不幸的是,我不能这样做,因为我有其他具有字符串/guid Id 的控制器。 “数字”约束会破坏这些。 可以定义多条路由。只需更改上面的代码以针对您的特定控制器,即routesTemplate: "api/items/id", defaults: new controller = "items"... 请看我上面的编辑。路由机制找到控制器没有问题。问题在于它认为所有三个操作都与请求匹配:PUT /api/items/5。我需要的是在未指定任何操作时匹配默认操作。希望能澄清事情。

以上是关于同一个 HttpVerb 的多个操作的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC AcceptVerbs 和注册路由

WebAPI学习WEBAPI笔记1_20180324

C# 从 HttpResponseMessage 读取

一个 BarButtonItem 的多个操作

如何为一个按钮添加多个操作

vbscript 一个单元格上的多个操作