多路由配置不适用于 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}
路由仍然适用。
我在 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}
路由仍然适用。