我的控制器只接受此网址上的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()
约束,它可以正常工作。有人知道我做错了吗?
答案 0 :(得分:8)
我把它放在评论中,但没有足够的空间。
编写自定义约束时,检查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;
}
}
答案 1 :(得分:4)
我会调试JsonConstraint
并查看内容类型是什么。
无论出于何种原因,它可能不是application/json
。
我知道那是RFC MIME类型,但是我已经看到了其他一些在我的时间流动的其他类型(例如text/x-json
),正如previous question中提到的那样。 / p>
另外,我从未见过ContentType约束,所以我有兴趣看看它是否有效。您是否尝试过使用其他MIME类型以防它出错?
最后,我不是只有一个JsonConstraint,而是创建一个通用的ContentTypeConstraint。
<强>更新强>
我在使用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。此外,如果您在枚举类中使用描述属性,则可以取消切换案例。