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

Custom Content-Type validation filter?

我想实现自定义内容类型验证过滤器,以便可以提供针对 415 不支持媒体类型的自定义错误模型。

像这样:

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 管道在执行任何自定义过滤器之前似乎 "catching" 不受支持或无效的 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));
        });
    ...
}

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

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

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