是否有可能在ASP.NET MVC中实现X-HTTP-Method-Override?
我正在实现一个使用ASP.NET MVC的RESTful API的原型,除了这里和那里的奇怪的错误之外,我已经实现了我在开始时设置的所有要求,除了来电者能够使用X-HTTP-Method-Override
自定义头来覆盖HTTP方法。是否有可能在ASP.NET MVC中实现X-HTTP-Method-Override?
我想的是,下面的请求......
GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE
...将被分派到实现DELETE
的功能,而不是GET
功能为行动(假设我的控制器方法有多种方法可以实现该操作,并且它们被标记为具有不同的[AcceptVerbs]
属性)。因此,考虑以下两种方法,我想上述请求分派到第二个:
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }
有谁知道这是可能的吗?这样做会有多少工作......?
您将无法使用的[AcceptVerbs]属性的,是因为它绑定到请求的实际的HTTP动词。幸运的是[AcceptVerbs]属性非常简单;您可以在http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431处查看源代码。
总之,子类AcceptsVerbsAttribute并重写IsValidForRequest()方法。实施将如下所示:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
X-HTTP-Method-Override
是一个自定义标题,很可能不受Web容器支持。
你是从网页打这个电话吗?如果是这样,你应该使用XmlHttpRequest
和DELETE
(或者你想要的任何动词)。更好的是,使用JS框架来为你完成繁重的工作。
您可以创建一个ActionFilter实现OnActionExecuting
,该控件在控制器操作被调用之前触发。然后,您可以询问请求标题,并根据X-HTTP-Method-Override
标题的值(如果存在)重定向。
在那一点上它不会已经完成了它认为它将要调用的动作的参数绑定?这些方法可能有不同的参数。我认为,也许我需要在动作被选中之前挂钩? – 2009-01-22 08:56:28
你看过Simply Restful Routing?它已经这样做了。
编辑2010年2月加入:方法重写内置到MVC 2
我没有看到它实现X-HTTP-Method-Override的任何事情,并且对源代码的快速扫描不会发现任何内容。你确定吗?如果可以的话,你可以指向我在其中实现的文件?干杯! – 2009-01-22 20:24:25
列维的答案是伟大的。此外,我还在检查FORM集合的自定义AcceptsVerbsAttribute中添加了一个检查,因此您可以简单地放置一个隐藏的输入来触发DELETE(类似于MVC 2的Html.HttpMethodOverride(HttpVerbs.Delete)
)。
<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />
更改incomingVerb分配:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;
要小心,这种方法!查看Stephen Walther的related post。
希望这可以帮助别人。
插入形成:
<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
这次谈话是有点老了,但我想和大家分享我已经使用MVC 2发现:
浏览器都支持两个HTTP动词:GET和POST,但ASP.NET MVC 2允许你使用Html.HttpMethodOverride helper方法来模拟Put,Get和Delete。在内部,这通过在X-HTTP-Method-Override表单字段中发送动词来实现。 HttpMethodOverride的行为所使用的作为新的短动词属性的[AcceptVerbs]属性,以及:
例如,行动宣言:
[ActionName("someresource")]
[HttpDelete]
public ActionResult DeleteSomeResource()
应该采取具有X你get请求责任-HTTP-Method-Override设置为Delete。
令人惊讶的是,这还没有被提及,但ASP.NET MVC本身支持X-HTTP-Method-Override,并且至少从版本2开始这样做。没有必要编写自定义代码处理这个(事情。
它以下列方式工作:
内AcceptVerbsAttribute(也由[HttpPut],[HttpPost]等为代表),有一个IsValidForRequest方法。内部的方法,它检查以Request.GetHttpMethodOverride(),它返回用以下条件适当被覆盖的HTTP方法:
- 重写只在POST请求支持。所有其他人都被忽略。
- 如果X-HTTP-Method-Override的值是GET或POST,它将被忽略。这是有道理的,因为你永远不需要用这些值覆盖。
- 它寻找X-HTTP-方法,覆盖在这个优先级以下地方: 1)HTTP头 2)表体 3)查询字符串
如果你真的很好奇,这里的GetHttpMethodOverride()的外观(从MVC 3的源代码):
public static class HttpRequestExtensions {
internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";
public static string GetHttpMethodOverride(this HttpRequestBase request) {
if (request == null) {
throw new ArgumentNullException("request");
}
string incomingVerb = request.HttpMethod;
if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
return incomingVerb;
}
string verbOverride = null;
string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(headerOverrideValue)) {
verbOverride = headerOverrideValue;
}
else {
string formOverrideValue = request.Form[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(formOverrideValue)) {
verbOverride = formOverrideValue;
}
else {
string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
verbOverride = queryStringOverrideValue;
}
}
}
if (verbOverride != null) {
if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
!String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
incomingVerb = verbOverride;
}
}
return incomingVerb;
}
}
我不会打电话了,我实现了它,而且我想使实现支持自定义头。 – 2009-01-21 23:59:50
我不明白。如果你控制这个实现,为什么你不会像使用标准动词那样使用HTTP? – Kevin 2009-01-22 01:30:16
因为不幸的是,有些客户端,代理服务器和防火墙不允许GET或POST以外的动词,所以有时候人们需要能够使用GET和PUT来伪造DELETE。这有点蹩脚,但大多数RESTful服务似乎都支持这个头文件。 – 2009-01-22 08:47:15