2009-01-21 16 views
5

Estoy implementando un prototipo de API RESTful usando ASP.NET MVC y aparte de los errores ocasionales aquí y allá, he logrado todos los requisitos que establecí al inicio, además de que los llamadores pueden usar el X-HTTP-Method-Override personalizado encabezado para anular el método HTTP.¿Es posible implementar X-HTTP-Method-Override en ASP.NET MVC?

Lo que me gustaría es que la petición siguiente ...

GET /someresource/123 HTTP/1.1 
X-HTTP-Method-Override: DELETE 

... sería enviado a mi método de control que implementa la funcionalidad DELETE en lugar de la funcionalidad GET para esa acción (suponiendo que hay varios métodos implementando la acción, y que están marcados con diferentes atributos [AcceptVerbs]). Por lo tanto, teniendo en cuenta los dos métodos siguientes, me gustaría que la mencionada solicitud para ser enviados a la segunda:

[ActionName("someresource")] 
[AcceptVerbs(HttpVerbs.Get)] 
public ActionResult GetSomeResource(int id) { /* ... */ } 

[ActionName("someresource")] 
[AcceptVerbs(HttpVerbs.Delete)] 
public ActionResult DeleteSomeResource(int id) { /* ... */ } 

¿Alguien sabe si esto es posible? ¿Y cuánto trabajo sería hacer eso ...?

Respuesta

5

Usted no será capaz de utilizar el atributo [AcceptVerbs] tal cual, ya que está ligado a verbo HTTP real de la petición. Afortunadamente, el atributo [AcceptVerbs] es muy simple; Puede ver la fuente usted mismo en http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.

En resumen, la subclase AceptaVerbsAtribuye e invalida el método IsValidForRequest(). La implementación sería algo como lo siguiente:

string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method; 
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase); 
+0

Tuve que copiar el código de AcceptVerbsAttribute e implementar el mío, ya que desafortunadamente está sellado, pero el enfoque funciona perfectamente y es agradable y simple, ¡así que parece que obtienes los 300 puntos! –

+0

hi levi, sin embargo, mi ASP.net IIS o MVC niega la solicitud DELETE y PUT, ¿hay alguna forma de hacerlo funcionar? Intenté poner Allow: PUT, DELETE en el encabezado IIS Allow, pero no funcionará ... – DucDigital

+0

Duc, sé que ha sido una MUCHA LARGA VEZ, pero compruebe si WebDav está instalado. Si es así, desinstálalo. De lo contrario, interceptará tus solicitudes PUT y DELETE. –

0

El X-HTTP-Method-Override es un encabezado personalizado y probablemente no sea compatible con su contenedor web.

¿Está llamando esto desde una página web? Si es así, probablemente debería usar XmlHttpRequest con DELETE (o cualquier verbo que desee). Mejor aún, use un marco JS para hacer el trabajo pesado por usted.

+0

no estoy llamando, estoy poniendo en práctica ... Y quiero que la aplicación admite la cabecera personalizada. –

+0

No entiendo. Si controlas la implementación, ¿por qué no usarías HTTP de la forma en que fue diseñado usando los verbos estándar? – Kevin

+2

porque desafortunadamente algunos clientes, servidores proxy y cortafuegos no permiten que los verbos que no sean GET o POST, por lo que a veces la gente tiene que ser capaz de falsificar DELETE con GET y PUT con POST. Es un poco cojo, pero la mayoría de los servicios RESTful parecen apoyar este encabezado. –

0

Puede crear un ActionFilter que implemente OnActionExecuting, que se dispara antes de invocar la acción del controlador. A continuación, puede interrogar a los encabezados de solicitud y redirigir en función del valor del encabezado X-HTTP-Method-Override, cuando esté presente.

+0

En ese momento, ¿no habrá hecho ya el enlace de parámetros para la acción que pensó que iba a llamar? Los métodos pueden tener diferentes parámetros. Creo que tal vez necesito conectarme antes de que el despachado seleccione la acción. –

1

¿Has mirado Simply Restful Routing? Ya lo hace.

Editado Feb 2010 para añadir: Método anulaciones se construyen en MVC 2.

+0

No veo nada al respecto al implementar X-HTTP-Method-Override y un escaneo rápido de la fuente no revela nada. ¿Estas seguro acerca de esto? Si es así, ¿podría indicarme el archivo en el que está implementado? ¡Aclamaciones! –

+0

X-HTTP-Method-Override es el diseño de una persona para admitir solicitudes no GET/POST. Simply Restful Routing es otro. Diseño diferente, mismo objetivo. –

+0

Realmente no quiero combinar REST con las URL de estilo RPC (estoy contento con una u otra, pero preferiría evitar una combinación de ambas) así que creo que prefiero ir con la opción de encabezado que con la acción enlaces como en el diseño Simply Restful. –

3

Levi's answer is great. Además, agregué un cheque en el AcceptsVerbsAttribute personalizado que también examina la colección FORM, por lo que simplemente puede poner una entrada oculta para desencadenar el DELETE (similar a MVC 2 Html.HttpMethodOverride(HttpVerbs.Delete)).

<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" /> 

cambiar la asignación a incomingVerb:

string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod; 

tener cuidado con este enfoque! Ver a related post por Stephen Walther.

Esperemos que esto ayude a alguien.

+0

Otra posible solución para enviarlo en el encabezado de tipo de contenido como parámetro de tipo MIME. – inf3rno

3

Insertar para formar:

<%= Html.HttpMethodOverride(HttpVerbs.Delete) %> 
2

Esta conversación es un poco viejo, pero quería compartir lo que he encontrado usando MVC 2:

navegadores soportan dos verbos HTTP: GET y POST, pero ASP.NET MVC 2 le permite simular Put, Get y Delete utilizando el método de ayuda Html.HttpMethodOverride. Internamente, esto funciona al enviar el verbo en un campo de formulario X-HTTP-Method-Override. El comportamiento de HttpMethodOverride es utilizado por el [AcceptVerbs] atributo, así como los nuevos atributos de verbo más corto:

Por ejemplo, la declaración de acción:

[ActionName("someresource")] 
[HttpDelete] 
public ActionResult DeleteSomeResource() 

debe asumir la responsabilidad de su solicitud get que tiene la X -HTTP-Method-Override establecido en Eliminar.

+0

No solo en el campo de formulario. Puede estar en encabezado o cadena de consulta también. La idea es que la anulación de método HTTP sea compatible. +1 –

1

Me sorprende que esto no se haya mencionado aún, pero ASP.NET MVC admite nativamente X-HTTP-Method-Override y lo ha estado haciendo desde al menos la versión 2. No es necesario escribir código personalizado para maneja esto.

que funcione de la siguiente manera:

Dentro AcceptVerbsAttribute (también aproxima por [HttpPut], [HttpPost], etc.), hay un método IsValidForRequest. Dentro de ese método, se comprueba con Request.GetHttpMethodOverride(), que devuelve el método HTTP overriden adecuado con las siguientes condiciones:

  • Overriding sólo se admite en solicitudes POST. Todos los demás son ignorados.
  • Si el valor X-HTTP-Method-Override es GET o POST, se ignora. Esto tiene sentido, ya que nunca necesitaría anular con estos valores.
  • busca X-HTTP-Method-Override en los siguientes lugares en esta prioridad: 1) encabezado HTTP 2) Cuerpo de la Forma 3) Cadena de consulta

Si usted es realmente curioso, aquí está cómo GetHttpMethodOverride() busca (desde el código fuente de 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; 
    } 
} 
Cuestiones relacionadas