多路径配置不适用于web api中的PUT和Delete操作

时间:2018-03-20 12:03:40

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

我在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或“获取”方法可以正常工作。

POST - &gt; http://localhost:56114/api/Test/

GET - &gt; http://localhost:56114/api/Test/

使用以下网址调用webapi控制器Save方法也可以正常工作。

POST - &gt; http://localhost:56114/api/Test/Save/1

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

PUT - &gt; http://localhost:56114/api/Test/3

DELETE - &gt; 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模式调用。

我想通过使用以下网址格式

来调用我上面的所有方法
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

2 个答案:

答案 0 :(得分:1)

看起来PUT和DELETE的请求路径与&#34; api / {controller} / {action} / {id}&#34;的路由模板匹配。即使请求路径可以匹配任何已定义的路由模板,也可以使用&#34; MapHttpRoute()&#34;注册的模板。首先要优先考虑。以下是路由解释PUT和DELETE请求路径的方法:

PUT:/ api / Test / 3 - &gt; / API /&LT;控制器&GT; /&lt;作用&GT;
DELETE:/ api / Test / 4 - &gt; / API /&LT;控制器&GT; /&lt;作用&GT;

使用可选的&#34; id&#34;在这种情况下已被忽略的值。

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

PUT:/ api / Test / DefaultAction / 3 - &gt; / API /&LT;控制器&GT; /&lt;作用&GT; /&LT; ID&GT;
DELETE:/ api / Test / DefaultAction / 4 - &gt; / API /&LT;控制器&GT; /&lt;作用&GT; /&LT; ID&GT;

您对GET和POST的请求正在运行,因为路径与第二个路由模板匹配,并且可选&#34; action&#34;和&#34; id&#34;参数。使用&#34; id&#34;在PUT和DELETE命令中,请求路径匹配第一个路径模板。

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

/ api / Save / 1 - &gt; / API /&LT;控制器&GT; /&lt;作用&GT;

所以&#34; Save&#34;方法&#34; TestController&#34;实际上并没有被这个请求调用。

答案 1 :(得分: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}路由。

相关问题