【问题标题】:Multiple route configuration does not work for PUT and Delete action in web api多路由配置不适用于 Web api 中的 PUT 和 Delete 操作
【发布时间】:2018-03-20 12:03:39
【问题描述】:

我在WebApiConfig 文件中配置了以下路由配置,以通过实际方法(操作)名称以及默认调用模式调用Web api控制器方法。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {

        config.MapHttpAttributeRoutes();
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));

        //By specifying action name 

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

        // Default calling pattern

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

    }
}

下面是控制器

public class TestController
{
    List<int> _lst;

    [ActionName("DefaultAction")]
    public HttpResponseMessage Get()
    {
        _lst = new List<int>() { 1, 2, 3, 4, 5 };
        return ToJson(_lst);
    }

    [ActionName("DefaultAction")]
    public HttpResponseMessage Post(int id)
    {
        _lst.Add(id);
        return ToJson(1);
    }

    [ActionName("DefaultAction")]
    public HttpResponseMessage Put(int id)
    {
       //doing sothing
        return ToJson(1);
    }

    [ActionName("DefaultAction")]
    public HttpResponseMessage Delete(int id)
    {
        //doing sothing
        return ToJson(1);
    }

    public HttpResponseMessage Save(int id)
    {
        //doing sothing
        return ToJson(1);
    }

    private HttpResponseMessage ToJson(dynamic obj)
    {
        var response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
        return response;
    }
}

使用以下 url 调用 webapi 控制器 Post 或“Get”方法工作正常,结果符合预期。

POST -> http://localhost:56114/api/Test/

GET -> http://localhost:56114/api/Test/

使用以下 url 调用 webapi 控制器 Save 方法也可以正常工作,结果符合预期。

POST -> http://localhost:56114/api/Test/Save/1

但是当我通过下面给定的 url 调用 api 控制器的 PUT 或 DELETE 方法时,它不会调用任何 (PUT/DELETE) 方法

PUT -> http://localhost:56114/api/Test/3

删除 -> http://localhost:56114/api/Test/4

它给出以下错误信息

{
    "Message": "No HTTP resource was found that matches the request URI 'http://localhost:56114/api/Test/3'.",
    "MessageDetail": "No action was found on the controller 'Test' that matches the name '3'."
}

任何人都可以帮助我解决为什么默认 URL 模式没有调用 PUT 和 DELETE 方法。

我想使用以下 URL 模式调用我上面的所有方法

POST -> http://localhost:56114/api/Test/   -> should call Post
GET -> http://localhost:56114/api/Test/    -> should call Get
PUT -> http://localhost:56114/api/Test/3   -> should call Put 
DELETE -> http://localhost:56114/api/Test/4  -> should call Delete
POST -> http://localhost:56114/api/Test/Save/1  -> should call Save

【问题讨论】:

  • 问题是参数名称:int value 如果您将它们重命名为int id,那么它可能会起作用或在您的方法上方添加属性:[Route("{value:int}] 还有,@ 是什么987654336@被用来做什么?是来自mvc而不是webapi,你应该使用RouteAttribute
  • 感谢@Ric,我已将“int value”更改为“int id”,将 [ActionName("DefaultAction")] 更改为 [RouteAttribute("DefaultAction")] 和默认值:new { action = "DefaultAction", id = RouteParameter.Optional } 到默认值:new { Name = "DefaultAction", id = RouteParameter.Optional } 但它仍然不起作用,即使现在我通过“Post”调用方法它总是调用“public HttpResponseMessage仅限 Save(int id)" 方法。
  • 从你的方法中移除 [ActionName("DefaultAction")] 然后调用它们。
  • @Ric,你的意思是说删除 [RouteAttribute("DefaultAction")] 因为我已经用 [RouteAttribute("DefaultAction")] 替换了所有 [ActionName("DefaultAction")] ?
  • 您的示例中实际上并不需要它们,为了清楚起见,可能值得在您的方法签名上方添加[HttpPost][HttpPut]。但除非您的方法名称与您想要调用的名称完全不同,否则没有真正的理由使用它们。

标签: asp.net-mvc asp.net-web-api2 postman


【解决方案1】:

转换为答案。

我认为您使用的 ActionNameAtrribute 来自 MVC,而不是 web api,所以删除它,在这种情况下它不会做任何事情。

以下是我认为适合您的方法:

[HttpGet]
public HttpResponseMessage Get()
{
    _lst = new List<int>() { 1, 2, 3, 4, 5 };
    return ToJson(_lst);
}

[HttpPost]
public HttpResponseMessage Post(int id)
{
    _lst.Add(id);
    return ToJson(1);
}

[HttpPut]
public HttpResponseMessage Put(int id)
{
    //doing sothing
    return ToJson(1);
}

[HttpDelete]
public HttpResponseMessage Delete(int id)
{
    //doing sothing
    return ToJson(1);
}

[HttpPost, Route("~/api/tests/save/{id}")]
public HttpResponseMessage Save(int id)
{
    //doing sothing
    return ToJson(1);
}

webapiconfig.cs:

 config.MapHttpAttributeRoutes();

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

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

以下模式现在应该可以工作了,注意我已经修改了你的第一个 post 调用,因为参数 id 存在。

POST -> http://localhost:56114/api/Test/1   -> should call Post
GET -> http://localhost:56114/api/Test/    -> should call Get
PUT -> http://localhost:56114/api/Test/3   -> should call Put 
DELETE -> http://localhost:56114/api/Test/4  -> should call Delete
POST -> http://localhost:56114/api/Test/Save/1  -> should call Save

您的默认路由以及更具体的api/{controller}/{action}/{id} 路由仍然适用。

【讨论】:

  • 我需要更改 WebApiConfig 文件上的任何内容吗?就像示例中所示的开发一样。
  • 不应该的,你测试过吗?
  • 这仅适用于 POST -> localhost:56114/api/Test/Save/1 所有其他现在给出与我的示例中所示相同的错误
  • 请立即尝试。
  • 谢谢@Ric,我现在不在办公室,开发人员访问受到限制,明天试试,让你知道..
【解决方案2】:

看起来 PUT 和 DELETE 的请求路径与“api/{controller}/{action}/{id}”的路由模板匹配。即使请求路径可以匹配任一定义的路由模板,首先使用“MapHttpRoute()”注册的模板将优先。以下是路由如何解释 PUT 和 DELETE 请求路径:

PUT: /api/Test/3 -> /api//
删除:/api/Test/4 -> /api//

本例中省略了可选的“id”值。

您可以通过切换路由的注册顺序来解决此问题,尽管它可能会影响您未在此处列出的其他路由。或者,您可以将目标操作显式添加到请求路径中:

PUT: /api/Test/DefaultAction/3 -> /api///
删除:/api/Test/DefaultAction/4 -> /api///

由于路径与带有可选“action”和“id”参数的第二个路由模板相匹配,因此您对 GET 和 POST 的请求正在运行。在 PUT 和 DELETE 命令中使用“id”会导致请求路径匹配第一个路由模板。

我也不确定为什么在您的示例中成功调用了“Save”操作(除非您有一个名为“SaveController”的控制器,但您没有在此处显示)。根据您的路由逻辑,该路径将被解释为:

/api/Save/1 -> /api//

所以“TestController”中的“Save”方法实际上并没有被这个请求调用。

【讨论】:

  • 感谢@Matthew,我已经更正了调用 URL 的“保存”方法,它是拼写错误。 Matthew 你能给我在 webapi2 中实现此功能的正确方法吗,我的要求是默认方法,如“GET、POST、PUT 和 DELETE”应该与默认 URL 路由一起使用,特定方法应该与具有特定操作名称的 url 一起使用。我已经更新了我想要调用哪个 URL 的问题,检查我的问题的最后陈述。
  • 尝试重新排序“WebApiConfig”类中的路由代码块,使带有“//通过指定操作名称”注释的块出现在带有“//默认调用模式”注释的块下方。在本示例的上下文中,这可能足以完成您想要的。
猜你喜欢
  • 1970-01-01
  • 2017-08-26
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2018-09-04
  • 2012-07-29
  • 1970-01-01
  • 2018-10-05
相关资源
最近更新 更多