当请求具有不受支持的Content-Type时,如何配置ASP.NET Web API服务返回的状态代码?

Law*_*ton 4 content-negotiation asp.net-web-api

如果向我的Web API服务发出请求Content-Type,该服务的标头包含该服务不支持的类型,则会返回500 Internal Server Error状态代码,其中包含类似于以下内容的消息:

{"Message":"An error has occurred.","ExceptionMessage":"No MediaTypeFormatter is available to read an object of type 'MyDto' from content with media type 'application/UnsupportedContentType'.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)
   at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)
   at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)
   at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"}
Run Code Online (Sandbox Code Playgroud)

我宁愿415 Unsupported Media Type按照建议返回状态代码,例如,这里.

如何配置我的服务来执行此操作?

Law*_*ton 5

这是我提出的解决这个问题的方法.

它广泛基于此处描述的用于在没有可接受的响应内容类型时发送406 Not Acceptable状态代码的情况.

public class UnsupportedMediaTypeConnegHandler : DelegatingHandler {
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                           CancellationToken cancellationToken) {
        var contentType = request.Content.Headers.ContentType;
        var formatters = request.GetConfiguration().Formatters;
        var hasFormetterForContentType = formatters //
            .Any(formatter => formatter.SupportedMediaTypes.Contains(contentType));

        if (!hasFormetterForContentType) {
            return Task<HttpResponseMessage>.Factory //
                .StartNew(() => new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
        }

        return base.SendAsync(request, cancellationToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

在设置服务配置时:

config.MessageHandlers.Add(new UnsupportedMediaTypeConnegHandler());
Run Code Online (Sandbox Code Playgroud)

请注意,这要求char集也匹配.您可以通过仅检查MediaType标题的属性来放松此限制.

  • 我采用了这个解决方案,但遇到了一个小问题.对于GET请求,代码仍然运行,并且找不到"null"内容类型的格式化程序(或我的应用程序中的"text/plain").所以要修复我只是检查一下它是否是GET请求,如果是,则跳过Formatter检查... (2认同)