DelegatingHandler在WebApi中解压缩传入的请求

在我的应用程序中,我们从客户端发送适当大小的数据包并接收相当大的响应,所以我想在上升和返回的过程中实现一些压缩。

在回来的路上很好,因为我可以依靠IIS的动态压缩来为我做这件事,但在上升的过程中,我发现了以下问题。

我有一个委托处理程序,用于解压缩传入的请求:(大部分代码基于Fabrik.Common的部分( https://github.com/benfoster/Fabrik.Common ))

public class DecompressionHandler : DelegatingHandler { public Collection Compressors; public DecompressionHandler() { Compressors = new Collection {new GZipCompressor(), new DeflateCompressor()}; } protected async override Task SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { if (request.Content.Headers.ContentEncoding.IsntNullOrEmpty() && request.Content != null) { var encoding = request.Content.Headers.ContentEncoding.First(); var compressor = Compressors.FirstOrDefault(c => c.EncodingType.Equals(encoding, StringComparison.InvariantCultureIgnoreCase)); if (compressor != null) { request.Content = await DecompressContentAsync(request.Content, compressor).ConfigureAwait(true); } } var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(true); return response; } private static async Task DecompressContentAsync(HttpContent compressedContent, ICompressor compressor) { using (compressedContent) { var decompressed = new MemoryStream(); await compressor.Decompress(await compressedContent.ReadAsStreamAsync(), decompressed).ConfigureAwait(true); // set position back to 0 so it can be read again decompressed.Position = 0; var newContent = new StreamContent(decompressed); // copy content type so we know how to load correct formatter newContent.Headers.ContentType = compressedContent.Headers.ContentType; return newContent; } } } public class DeflateCompressor : Compressor { private const string DeflateEncoding = "deflate"; public override string EncodingType { get { return DeflateEncoding; } } public override Stream CreateCompressionStream(Stream output) { return new DeflateStream(output, CompressionMode.Compress, leaveOpen: true); } public override Stream CreateDecompressionStream(Stream input) { return new DeflateStream(input, CompressionMode.Decompress, leaveOpen: true); } } public abstract class Compressor : ICompressor { public abstract string EncodingType { get; } public abstract Stream CreateCompressionStream(Stream output); public abstract Stream CreateDecompressionStream(Stream input); public virtual Task Compress(Stream source, Stream destination) { var compressed = CreateCompressionStream(destination); return Pump(source, compressed) .ContinueWith(task => compressed.Dispose()); } public virtual Task Decompress(Stream source, Stream destination) { var decompressed = CreateDecompressionStream(source); return Pump(decompressed, destination) .ContinueWith(task => decompressed.Dispose()); } protected virtual Task Pump(Stream input, Stream output) { return input.CopyToAsync(output); } } public interface ICompressor { string EncodingType { get; } Task Compress(Stream source, Stream destination); Task Decompress(Stream source, Stream destination); } public class GZipCompressor : Compressor { private const string GZipEncoding = "gzip"; public override string EncodingType { get { return GZipEncoding; } } public override Stream CreateCompressionStream(Stream output) { return new GZipStream(output, CompressionMode.Compress, leaveOpen: true); } public override Stream CreateDecompressionStream(Stream input) { return new GZipStream(input, CompressionMode.Decompress, leaveOpen: true); } } 

解压缩工作正常,我有我的request.Content填充结果是我的解压缩JSON。

当我将它传递给base.SendAsync并且它命中我的控制器方法时,模型为null,而在我实现压缩之前,它一切都很好。

我已经读过,当您阅读内容流时,它是一次性的事情,但我认为将request.content设置为解压缩的结果应该让它再次被读取?

我解决了这个问题

在我的HTTPClient实现中,我已经从使用PostAsJsonAsync转移到PostAsync来执行压缩客户端,但是没有添加Content-Type标头来指定application / json。

在客户端完成此操作之后,所有操作都按计划进行。