多路由配置不适用于 Web 中的 PUT 和删除操作 api

Multiple route configuration does not work for PUT and Delete action in web api

我在 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;
    }
}

调用 webapi 控制器 Post 或 'Get' 方法使用下面的 url 工作正常,结果如预期。

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

获取 -> http://localhost:56114/api/Test/

调用 webapi 控制器 Save 方法与下面 url 也正常工作,结果如预期。

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'."
}

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

我想使用以下 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

看起来 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///

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

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

/api/Save/1 -> /api/<控制器>/<操作>

因此 "TestController" 中的 "Save" 方法实际上并未被此请求调用。

正在转换为答案。

我认为您使用的 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} 路由仍然适用。