4

我想实现自定义 Content-Type 验证过滤器,以便可以提供 415 Unsupported Media Type 上的自定义错误模型。

像这样的东西:

public class ValidateContentTypeFilterAttribute : ActionFilterAttribute
{
    private const string JsonMimeType = "application/json";

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        string requestMethod = context.HttpContext.Request.Method.ToUpper();

        if (requestMethod == WebRequestMethods.Http.Post || requestMethod == WebRequestMethods.Http.Put)
        {
            if (request.ContentType != JsonMimeType)
            {
                // "Unsupported Media Type" HTTP result.
                context.Result = new HttpUnsupportedMediaTypeResult();
                return;
            }
        }
    }
}

问题是 MVC 管道似乎在执行任何自定义过滤器之前“捕获”了不受支持或无效的 Content-Type 值。即使是“application/xml”内容类型也会被拒绝。

这将在哪里配置?

我的 MVC 配置仅包含以下内容:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .AddJsonOptions(options =>
        {
            options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include;
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            options.SerializerSettings.Converters.Add(new SquidJsonConverter());
        })
        .AddMvcOptions(options =>
        {
            options.Filters.Add(typeof(ValidateAntiForgeryTokenAttribute));
            options.Filters.Add(typeof(ValidateContentTypeFilterAttribute));
            options.Filters.Add(typeof(ValidateAcceptFilterAttribute));
            options.Filters.Add(typeof(ValidateModelFilterAttribute));
        });
    ...
}
4

1 回答 1

6

对于您在此处尝试实现的目标,操作过滤器在处理管道中为时已晚。

“传入”请求的过滤器执行顺序如下:

  1. 授权过滤器的OnAuthorization..方法调用
  2. 资源过滤器的OnResourceExecuting..方法调用模型
  3. 发生模型绑定(这是进行内容类型检查的地方)
  4. 动作过滤器的OnActionExecuting..方法调用
  5. 动作执行发生

您可以改为创建资源过滤器。一个例子:

public class CustomResourceFilter : IResourceFilter
{
    private readonly string jsonMediaType = "application/json";

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }

    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        if (context.HttpContext.Request.Method == "PUT" || context.HttpContext.Request.Method == "POST")
        {
            if (!string.Equals(
                MediaTypeHeaderValue.Parse(context.HttpContext.Request.ContentType).MediaType,
                jsonMediaType,
                StringComparison.OrdinalIgnoreCase))
            {
                context.Result = new JsonResult(new { Error = "An error message here" }) { StatusCode = 415 };
            }
        }
    }
}

如果您想修改所有类型的UnsupportedMediaTypeResult响应,那么您可以编写一个结果过滤器。

传出响应的过滤器管道是:

  1. 动作过滤器的OnActionExecuted...方法调用
  2. 结果过滤器的OnResultExecuting..方法调用
  3. 结果过滤器的OnResultExecuted..方法调用
  4. 资源过滤器的OnResourceExecuted..方法调用

带有结果过滤器的示例:

public class CustomResultFilter : ResultFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        var result = context.Result as UnsupportedMediaTypeResult;
        if (result != null)
        {
            context.Result = new JsonResult(new { Error = "An error message here" }) { StatusCode = 415 };
        }
    }
}
于 2016-07-08T19:39:24.063 回答