自定义内容类型验证过滤器?

时间:2016-07-08 17:45:53

标签: asp.net-core asp.net-core-mvc asp.net-core-1.0 asp.net-mvc-filters

我想实现自定义内容类型验证过滤器,以便可以提供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));
        });
    ...
}

1 个答案:

答案 0 :(得分:6)

在处理管道中,动作过滤器为时已晚,无法实现此目的。

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

  1. 授权过滤器' OnAuthorization..方法调用
  2. 资源过滤器' OnResourceExecuting..方法调用模型
  3. 发生模型绑定(这是内容类型检查的位置 制造)
  4. 动作过滤器' OnActionExecuting..方法调用
  5. 执行行动
  6. 您可以改为创建资源过滤器。一个例子:    

    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..方法调用
    5. 结果过滤器的示例:

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