2010-01-28 10 views
8

que tienen un controlador que sólo acepta un post en este URL:¿Cómo se usa una restricción personalizada con HttpMethodConstraint en el enrutamiento ASP.NET MVC?

POST http://server/stores/123/products 

El puesto debe ser de tipo de contenido application/json, así que esto es lo que tengo en mi tabla de enrutamiento:

routes.MapRoute(null, 
       "stores/{storeId}/products", 
       new { controller = "Store", action = "Save" }, 
       new { 
         httpMethod = new HttpMethodConstraint("POST"), 
         json = new JsonConstraint() 
        } 
       ); 

donde JsonConstraint es:

public class JsonConstraint : IRouteConstraint 
{ 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     return httpContext.Request.ContentType == "application/json"; 
    } 
} 

Cuando utilizo la ruta, aparece un 405 Prohibido:

The HTTP verb POST used to access path '/stores/123/products' is not allowed

Sin embargo, si se quita la restricción json = new JsonConstraint(), que funciona bien. ¿Alguien sabe lo que estoy haciendo mal?

+0

favor puede publicar su fragmento de jQuery? He realizado algunas pruebas adicionales y muestra que ContentType se muestra como "application/xml". –

+0

Estoy usando un complemento de Firefox llamado 'REST Client' para probarlo. –

Respuesta

8

Pondré esto en un comentario pero no hay suficiente espacio.

Al escribir una restricción personalizada, es muy importante inspeccionar el parámetro routeDirection y asegurarse de que su lógica se ejecute solo en el momento correcto.

Este parámetro le dice si su restricción se está ejecutando mientras procesa una solicitud entrante o se está ejecutando mientras alguien está generando una URL (como cuando llaman al Html.ActionLink).

En su caso creo que usted quiere poner todo el código correspondiente en un gigante "si":

public bool Match(HttpContextBase httpContext, Route route, 
    string parameterName, RouteValueDictionary values, 
    RouteDirection routeDirection) 
{ 
    if (routeDirection == RouteDirection.IncomingRequest) { 
     // Only check the content type for incoming requests 
     return httpContext.Request.ContentType == mimeType; 
    } 
    else { 
     // Always match when generating URLs 
     return true; 
    } 
} 
+0

Buena respuesta, pero ¿no deberíamos usar 'Aceptar' en lugar de' ContentType'? http://stackoverflow.com/a/15898503/1804678 – Jess

+0

@Jess la pregunta original específicamente mencionó 'ContentType'. El 'ContentType' indica el formato del cuerpo de la solicitud, mientras que el encabezado' Accept' indica el * deseado * formado del cuerpo de la respuesta. – Eilon

4

Quisiera depurar el JsonConstraint y ver cuál es el tipo de contenido. Es posible que, por cualquier razón, no sea application/json.

Sé que ese es el tipo RFC MIME, pero he visto algunos otros flotando en mi tiempo (como text/x-json), como se ha mencionado aquí en un previous question.

Además, nunca he visto una restricción ContentType, por lo que me gustaría ver si funciona. ¿Lo has probado con otros tipos MIME en caso de que sea defectuoso?

Y finalmente, en lugar de tener solo una JsonConstraint, crearía una ContentTypeConstraint genérica.

Actualización:

Toqué juntos un método WebRequest rápida en una ruta que utiliza el código ContentTypeConstraint, y que parece que funciona correctamente.

Enum

public enum ConstraintContentType 
{ 
    XML, 
    JSON, 
} 

clase de restricciones

public class ContentTypeConstraint : IRouteConstraint 
{ 
    private string mimeType; 

    public ContentTypeConstraint(ConstraintContentType constraintType) 
    { 
    //FYI: All this code could be redone if you used the Description attribute, and a ToDescription() method. 
    switch (constraintType) 
    { 
     case ConstraintContentType.JSON: 
     mimeType = "application/json"; 
     break; 
     case ConstraintContentType.XML: 
     mimeType = "text/xml"; 
     break; 
     default: 
     mimeType = "text/html"; 
     break; 
    } 
    } 

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
    //As suggested by Eilon 
    if (routeDirection == RouteDirection.UrlGeneration) 
     return true; 

    return httpContext.Request.ContentType == mimeType; 
    } 
} 

Esto se llama, usando su ejemplo, como:

contentType = new ContentTypeConstraint(ConstraintContentType.JSON) 

Esta fue la restricción es reutilizable para Mu ch más que solo JSON. Además, la caja del conmutador se puede eliminar si usa atributos de descripción en la clase enum.

+0

Gracias por la actualización y publicación en el blog. –

+0

@Jess Lo es. Lamentablemente, saqué mi blog hace algunos años, pero la respuesta sigue siendo válida (aunque bastante antigua). –

Cuestiones relacionadas