【问题标题】:How do I use a custom constraint with a HttpMethodConstraint in ASP.NET MVC routing?如何在 ASP.NET MVC 路由中使用带有 HttpMethodConstraint 的自定义约束?
【发布时间】:2010-01-28 23:26:12
【问题描述】:

我有一个只接受这个 URL 上的 POST 的控制器:

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

POST 应该是内容类型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 Forbidden:

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

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

【问题讨论】:

  • 请问您能发布您的 jQuery sn-p 吗?我已经运行了一些进一步的测试,它显示 ContentType 显示为“application/xml”。
  • 我正在使用一个名为 REST Client 的 Firefox 插件来测试它。

标签: asp.net-mvc routing asp.net-mvc-routing


【解决方案1】:

我想把它放在评论中,但没有足够的空间。

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

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

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

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;
    }
}

【讨论】:

  • 很好的答案,但我们不应该使用Accept 而不是ContentType 吗? stackoverflow.com/a/15898503/1804678
  • @Jess 特别提到的原始问题ContentTypeContentType 表示请求正文的格式,而Accept 标头表示由响应正文构成的desired
  • 在生成 Url 时有什么特别的理由默认为 true 吗?谢谢
  • @AleksanderBethke - 这取决于场景,但根据我的经验,大多数人大多数时候只希望为传入的 URL 运行约束逻辑。对于 URL 生成,他们只希望所有内容都匹配,因为约束通常匹配在 URL 生成中没有逻辑等效项的内容(例如请求内容类型标头)。没有对错,只是常见的模式。
【解决方案2】:

我会调试JsonConstraint 并查看内容类型是什么。

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

我知道那是 RFC MIME 类型,但我在我的时代看到过其他一些类型(例如 text/x-json),正如在 previous question 中提到的那样。

另外,我从未见过 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。此外,如果您在枚举类上使用描述属性,则可以取消 switch case。

【讨论】:

  • @Jess 是。可悲的是,几年前我删除了我的博客,但答案的内容仍然有效(尽管已经很老了)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
  • 2013-12-25
相关资源
最近更新 更多