如何在 ASP.NET MVC 路由中将自定义约束与 HttpMethodConstraint 结合使用?

发布于 2024-08-19 12:28:02 字数 1074 浏览 3 评论 0原文

我有一个仅接受此 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 code> 是:

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() 约束,它工作正常。有人知道我做错了什么吗?

I have a controller that only accepts a POST on this URL:

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

The POST should be of content-type application/json, so this is what I have in my routing table:

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

Where JsonConstraint is:

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

When I use the route, I get a 405 Forbidden:

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

However, if I remove the json = new JsonConstraint() constraint, it works fine. Does anybody know what I'm doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

守不住的情 2024-08-26 12:28:02

我想把它放在评论中,但空间不够。

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

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

在你的情况下,我认为你想把所有匹配的代码放在一个巨大的“if”中:

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

I'd put this in a comment but there isn't enough space.

When writing a custom constraint it is very important to inspect the routeDirection parameter and make sure that your logic runs only at the right time.

That parameter tells you whether your constraint is being run while processing an incoming request or being run while someone is generating a URL (such as when they call Html.ActionLink).

In your case I think you want to put all your matching code in a giant "if":

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;
    }
}
风为裳 2024-08-26 12:28:02

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

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

我知道那是 RFC MIME 类型,但我见过一些其他类型(例如 text/x-json),正如 上一个问题

另外,我从未见过 ContentType 约束,所以我有兴趣看看它是否有效。您是否尝试过使用其他 MIME 类型以防万一出现问题?

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

更新:

我在使用 ContentTypeConstraint 代码的路由上组合了一个快速 WebRequest 方法,并且该方法似乎工作正常。

Enum

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。

I would debug the JsonConstraint and see what the content type is.

It's possible that, for whatever reason, it may not be application/json.

I know that that is the RFC MIME type, but I've seen a few others floating around in my time (such as text/x-json), as has been mentioned here in a previous question.

Also, I've never seen a ContentType constraint, so I'd be interested to see if it works. Have you tried it with other MIME types just in case it's faulty?

And finally, rather than have just a single JsonConstraint, I'd create a generic ContentTypeConstraint.

Update:

I knocked together a quick WebRequest method on a route that uses the ContentTypeConstraint code, and that seems to work correctly.

Enum

public enum ConstraintContentType
{
  XML,
  JSON,
}

Constraint class

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

This would be called, using your example, as:

contentType = new ContentTypeConstraint(ConstraintContentType.JSON)

This was the constraint is reusable for much more than just JSON. Also, the switch case can be done away with if you use description attributes on the enum class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文