我有一个自托管的WebApi。 我的客户端正在发送一个GZip压缩流,我有一个属性,它在ActionFilterAttribute的OnActionExecuting覆盖中解压缩流。
但是我在控制器中的Details对象始终为null。
public class DatabaseAPIController : ApiController
{
[Decompression]
public bool PostDetails([FromBody] IEnumerable<Detail> Details)
{
// The Details object is null.
// This writes out the correct JSON which has been decompressed which proves my decompression method works.
Console.WriteLine(Request.Content.ReadAsStringAsync().Result);
// Do other work.
return true;
}
}
这是解压缩属性。
public class DecompressionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var content = actionContext.Request.Content;
var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result;
var decompressedContent = bytes == null ? new byte[0] : CompressionHelper.Decompress(bytes);
actionContext.Request.Content.Headers.Clear();
actionContext.Request.Content = new StringContent(Encoding.UTF8.GetString(decompressedContent), Encoding.UTF8, "application/json");
base.OnActionExecuting(actionContext);
}
}
如果我从客户端删除压缩和从服务器解压缩属性,那么一切正常。
我无法弄清楚为什么我的解压缩JSON不会填充PostDetails方法中的Details对象。
完整答案
public class DecompressionHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var content = request.Content;
var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result;
var decompressedContent = bytes == null ? new byte[0] : CompressionHelper.Decompress(bytes);
request.Content.Headers.Clear();
request.Content = new StringContent(Encoding.UTF8.GetString(decompressedContent), Encoding.UTF8, "application/json");
request.Content.Headers.Add("Content-Length", decompressedContent.Length.ToString());
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
我在自托管设置的构造函数中注册了我的处理程序。
public partial class MainWebAPI : ServiceBase
{
private HttpSelfHostServer _server;
private readonly HttpSelfHostConfiguration _config;
public const string ServiceAddress = "http://localhost:2345";
public MainWebAPI()
{
InitializeComponent();
_config = new HttpSelfHostConfiguration(ServiceAddress);
_config.MessageHandlers.Add(new DecompressionHandler());
_config.Routes.MapHttpRoute("DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
}
答案 0 :(得分:1)
我猜可能在OnActionExecuting期间已经发生了参数绑定,所以无论你在做什么,模型绑定器都不会看到它。
我认为你应该尝试使用MessageHandler:
public class CompressedMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for compressed message
// Change the request
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
消息处理程序适用于在HTTP消息级别(而不是控制器操作)上运行的横切关注点。例如,消息处理程序可能会读取或修改请求标头。
这或多或少(内容)你在这里尝试做什么。
您不再需要[Decompression]
属性(这很好);您将需要使用客户端的自定义http标头来指示您正在接收的内容被压缩的处理程序;或多或少与发送压缩响应时发生的情况相同(由系统管理,而不是由您手动管理)。