的X HTTP的方法,覆盖给予NOTFOUND(404)上的ASP.NET Web API [英] X-HTTP-Method-Override gives NotFound (404) on ASP.NET Web API
问题描述
我想实现以下<描述的步骤A HREF HTTP方法覆盖=http://www.asp.net/web-api/overview/working-with-http/http-message-handlers相对= nofollow的>此处。基本上,我创建一个DelegatingHandler,类似以下内容,将其添加为消息处理程序上的Application_Start
。
公共类MethodOverrideHandler:DelegatingHandler
{
只读的String [] = _methods {删除,HEAD,PUT};
常量字符串_header =X-HTTP-方法-覆盖; 保护覆盖任务&LT; Htt的presponseMessage&GT; SendAsync(
HTT prequestMessage请求的CancellationToken的CancellationToken)
{
//检查HTTP POST与X-HTTP-方法,覆盖头部。
如果(request.Method == HttpMethod.Post&放大器;&安培; request.Headers.Contains(_header))
{
//检查头值是在我们的方法列表。
VaR方法= request.Headers.GetValues(_header).FirstOrDefault();
如果(_methods.Contains(方法,StringComparer.InvariantCultureIgnoreCase))
{
//改变请求方法。
request.Method =新列举HTTPMethod(法);
}
}
返回base.SendAsync(请求的CancellationToken);
}
}
我有我的控制器定义了以下方法:
-
人/ {ID}
,GET -
人/ {ID}
,PUT -
人/ {ID}
,删除
我可以叫他们通过自己的本土的方法和他们的工作预期。然而,当我试着打电话给他们通过POST,用删除或PUT发送 X-HTTP-方法,覆盖
头,它给出了一个未找到(404)错误。补充一点,当它给这个错误,它从来没有达到这一点很重要的 MethodOverrideHandler
- 我已经把断点是从不打;它命中断点,当我打电话正常DELETE和PUT。
我甚至尝试添加另一种方法:
-
人/ {ID}
,POST
当我这样做,我得到的不允许的方法(405)代替。
我以为消息处理程序进行路由和控制调度员之前运行。这是为什么给我404?
我不认为这是相关的,但我不使用默认的Web API路由。相反,我使用的是自定义属性,分配给每个方法映射,如:
routes.MapHttpRoute(
的String.Format({0} _ {1},operation.Name,service.ServiceId)
的String.Format({0} / {1},service.Route preFIX,routeTemplateAttribute.Template)
默认值,
新{列举HTTPMethod = GetHttpMethodConstraint(操作)});
[HttpDelete,RouteTemplate(人/(编号))
公众的Htt presponseMessage deletePerson的(字符串ID)
{
// ...
}
修改: GetHttpMethodConstraint
code是低于
私有静态HttpMethodConstraint GetHttpMethodConstraint(MethodInfo的MethodInfo的)
{
VAR methodResolver = HttpMethodResolver.FromMethodInfo(MethodInfo的);
返回新HttpMethodConstraint(methodResolver.Resolve());
}
内部类HttpMethodResolver
{
私人MethodInfo的_MethodInfo; 私人HttpMethodResolver(MethodInfo的MethodInfo的)
{
_MethodInfo = MethodInfo的;
} 公共静态HttpMethodResolver FromMethodInfo(MethodInfo的MethodInfo的)
{
返回新HttpMethodResolver(MethodInfo的);
} 公共字符串[]解决()
{
VAR动词=新的List&LT;&列举HTTPMethod GT;(); 如果(MethodHasAttribute&LT; HttpGetAttribute&GT;())
{
verbs.Add(HttpMethod.Get);
}
否则,如果(MethodHasAttribute&LT; HttpPostAttribute&GT;())
{
verbs.Add(HttpMethod.Post);
}
否则,如果(MethodHasAttribute&LT; HttpDeleteAttribute&GT;())
{
verbs.Add(HttpMethod.Delete);
}
否则,如果(MethodHasAttribute&LT; HttpPutAttribute&GT;())
{
verbs.Add(HttpMethod.Put);
}
其他
{
抛出新ServiceModelException(HTTP方法属性应使用);
} 返回verbs.Select(V =&GT; v.Method).ToArray();
} 私人布尔MethodHasAttribute&LT; T&GT;()其中T:属性
{
返回GetMethodAttribute&LT; T&GT;()!= NULL;
} 私人ŧGetMethodAttribute&LT; T&GT;()其中T:属性
{
返回_methodInfo.GetCustomAttributes(typeof运算(T),真).FirstOrDefault()为T;
}
}
我试图重现你的错误,但我不能。在这里,你可以下载我简单的项目,消息处理程序: HTTPS://dl.dropbox。 COM / U / 20568014 / WebApplication6.zip
我想指出的是执行的操作选择逻辑之前运行的消息处理程序。所以,你的情况,可能是别的东西,因为出现问题导致的问题,我想你应该看看你的其他消息处理,消息处理程序的注册code等原因在于消息处理程序永远不会运行的事实。
另外,我觉得你的 IRouteConstraint
实施 GetHttpMethodConstraint
,看起来可疑我。
下面是我的注册code的消息处理程序:
保护无效的Application_Start(对象发件人,EventArgs的发送){ 无功配置= GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
DefaultHttpRoute
API / {}控制器/(编号),
新{ID = RouteParameter.Optional}
); config.MessageHandlers.Add(新MethodOverrideHandler());
}
I am trying to implement HTTP method override following the steps described here. Basically, I am creating a DelegatingHandler, similar to the following, and adding it as a message handler on Application_Start
.
public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
const string _header = "X-HTTP-Method-Override";
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for HTTP POST with the X-HTTP-Method-Override header.
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}
I have the following methods defined on my Controller:
persons/{id}
, GETpersons/{id}
, PUTpersons/{id}
, DELETE
I can call them through their "native" methods and they work as expected. However, when I try to call them through a POST, sending the X-HTTP-Method-Override
header with "DELETE" or "PUT", it gives a Not Found (404) error. It is important to add that, when it gives this error, it never reaches the MethodOverrideHandler
-- I have put a Breakpoint which is never hit; it does hit the Breakpoint when I call normal DELETE and PUT.
I even tried adding another method:
persons/{id}
, POST
When I do this, I get a Method Not Allowed (405) instead.
I thought that message handlers were run BEFORE the Routing and Controller dispatchers. Why is this giving me 404?
I do not think this is related, but I am not using default Web API routing. Instead, I am mapping using a custom Attribute, assigned to each method, like this:
routes.MapHttpRoute(
String.Format("{0}_{1}", operation.Name, service.ServiceId),
String.Format("{0}/{1}", service.RoutePrefix, routeTemplateAttribute.Template),
defaults,
new { httpMethod = GetHttpMethodConstraint(operation) });
[HttpDelete, RouteTemplate("persons/{id}")]
public HttpResponseMessage DeletePerson(string id)
{
// ...
}
EDIT: GetHttpMethodConstraint
code is below.
private static HttpMethodConstraint GetHttpMethodConstraint(MethodInfo methodInfo)
{
var methodResolver = HttpMethodResolver.FromMethodInfo(methodInfo);
return new HttpMethodConstraint(methodResolver.Resolve());
}
internal class HttpMethodResolver
{
private MethodInfo _methodInfo;
private HttpMethodResolver(MethodInfo methodInfo)
{
_methodInfo = methodInfo;
}
public static HttpMethodResolver FromMethodInfo(MethodInfo methodInfo)
{
return new HttpMethodResolver(methodInfo);
}
public string[] Resolve()
{
var verbs = new List<HttpMethod>();
if (MethodHasAttribute<HttpGetAttribute>())
{
verbs.Add(HttpMethod.Get);
}
else if (MethodHasAttribute<HttpPostAttribute>())
{
verbs.Add(HttpMethod.Post);
}
else if (MethodHasAttribute<HttpDeleteAttribute>())
{
verbs.Add(HttpMethod.Delete);
}
else if (MethodHasAttribute<HttpPutAttribute>())
{
verbs.Add(HttpMethod.Put);
}
else
{
throw new ServiceModelException("HTTP method attribute should be used");
}
return verbs.Select(v => v.Method).ToArray();
}
private bool MethodHasAttribute<T>() where T : Attribute
{
return GetMethodAttribute<T>() != null;
}
private T GetMethodAttribute<T>() where T : Attribute
{
return _methodInfo.GetCustomAttributes(typeof(T), true).FirstOrDefault() as T;
}
}
I have tried to reproduce your error but I wasn't able to. Here, you can download my simple project with your message handler: https://dl.dropbox.com/u/20568014/WebApplication6.zip
I would like to point out that message handlers run before the action selection logic is performed. So, in your case, probably something else causes the problem and I think you should look at your other message handlers, your message handler's registration code, etc because the problem occurs due to the fact that your message handler never runs.
Also, I think your IRouteConstraint
implementation, GetHttpMethodConstraint
, looks suspicious to me.
Here is my registration code for the message handler:
protected void Application_Start(object sender, EventArgs e) {
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
"DefaultHttpRoute",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
config.MessageHandlers.Add(new MethodOverrideHandler());
}
这篇关于的X HTTP的方法,覆盖给予NOTFOUND(404)上的ASP.NET Web API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!