Asp.net mvc 如何在ASP.NET MVC路由中使用带有HttpMethodConstraint的自定义约束?

Asp.net mvc 如何在ASP.NET MVC路由中使用带有HttpMethodConstraint的自定义约束?,asp.net-mvc,routing,asp.net-mvc-routing,Asp.net Mvc,Routing,Asp.net Mvc Routing,我有一个只接受此URL上帖子的控制器: POST http://server/stores/123/products 帖子的内容类型应该是application/json,因此这就是我在路由表中的内容: routes.MapRoute(null, "stores/{storeId}/products", new { controller = "Store", action = "Save" }, n

我有一个只接受此URL上帖子的控制器:

POST http://server/stores/123/products
帖子的内容类型应该是
application/json
,因此这就是我在路由表中的内容:

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

public class JsonConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return httpContext.Request.ContentType == "application/json";
    }
}
当我使用这条路线时,我得到一个405禁止:

不允许使用用于访问路径“/stores/123/products”的HTTP动词POST


但是,如果我删除
json=newJSONConstraint()
约束,它就可以正常工作。有人知道我做错了什么吗?

我会调试
JsonConstraint
并查看内容类型

无论出于何种原因,它可能不是
application/json

我知道这是RFC MIME类型,但我在我的时代看到过一些其他类型(如
text/x-json
),正如本文在一篇文章中提到的

另外,我从未见过ContentType约束,所以我想看看它是否有效。你有没有试过其他MIME类型,以防出现问题

最后,我将创建一个通用ContentTypeConstraint,而不是一个JsonConstraint

更新:

我在使用ContentTypeConstraint代码的路由上设计了一个快速WebRequest方法,该方法似乎工作正常

枚举

public enum ConstraintContentType
{
  XML,
  JSON,
}
约束类

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;
  }
}
使用您的示例,这将被称为:

contentType = new ContentTypeConstraint(ConstraintContentType.JSON)

这就是约束的可重用性,不仅仅是JSON。此外,如果在enum类上使用description属性,则可以取消开关大小写。

我会将其放在注释中,但没有足够的空间

编写自定义约束时,检查
routeDirection
参数并确保逻辑仅在正确的时间运行非常重要

该参数告诉您是在处理传入请求时运行约束,还是在某人生成URL时运行约束(例如当他们调用
Html.ActionLink

在您的情况下,我认为您希望将所有匹配的代码放入一个巨大的“如果”:


请发布jQuery代码片段好吗?我已经运行了一些进一步的测试,它显示ContentType显示为“application/xml”。我正在使用一个名为
REST-Client
的Firefox插件来测试它。回答得好,但我们不应该使用
Accept
而不是
ContentType
@Jess最初的问题特别提到了
ContentType
ContentType
表示请求主体的格式,而
Accept
头表示响应主体的所需格式。在生成URL时,是否有任何特定原因默认为true?Thanks@AleksanderBethke-这取决于场景,但根据我的经验,大多数人大多数时候只希望对传入URL运行约束逻辑。对于URL生成,他们只希望所有内容都匹配,因为约束通常与URL生成没有逻辑等价物的内容(例如请求内容类型头)匹配。没有错也没有对,只有共同的模式。@Jess就是这样。可悲的是,几年前我把我的博客撤了下来,但答案的基本内容仍然有效(尽管很旧)。
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;
    }
}