2013-08-15 2 views
2

내 응용 프로그램에서 클라이언트로부터 괜찮은 크기의 패킷을 보내고 적절한 크기의 응답을 수신하므로 일부 압축을 구현하고 싶을 때가 있습니다.WebApi에서 들어오는 요청의 압축을 푸는 DelegatingHandler

도중에 IIS의 동적 압축을 사용하여 나를 대신 할 수 있기 때문에 괜찮습니다.하지만 다음과 같은 문제가 있습니다. (이 코드의 대부분은 Fabrik.Common의 부품 (https://github.com/benfoster/Fabrik.Common)를 기반으로)

public class DecompressionHandler : DelegatingHandler 
{ 
    public Collection<ICompressor> Compressors; 

    public DecompressionHandler() 
    { 
     Compressors = new Collection<ICompressor> {new GZipCompressor(), new DeflateCompressor()}; 
    } 

    protected async override Task<HttpResponseMessage> 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<HttpContent> 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); 
    } 
} 

압축 해제가 잘 작동하고 내가 가진 :

나는 들어오는 요청을 압축 해제가 앉아 위임 핸들러가 내 요청. 압축 해제 된 JSON 결과가 컨텐츠에 채워집니다.

내가 base.SendAsync에 전달하고 내 컨트롤러 메서드를 눌렀을 때 모델이 null 인 반면 압축을 구현하기 전에는 모두 훌륭하게 작동했습니다.

콘텐츠 스트림을 읽을 때 한 번 읽는다고 읽었지만 request.content를 압축 해제 된 결과로 설정하면 다시 읽어야합니다.

답변

1

이 문제가 해결되었습니다.

압축 클라이언트 측에서 PostAsJsonAsync를 사용하여 PostAsJyncAsync에서 PostAsync로 이동했지만 Application-json을 지정하기 위해 Content-Type 헤더를 추가하지 않은 것은 HTTPClient 구현에서 오류입니다.

클라이언트에서이를 수행 한 후에 모두 계획대로 작동합니다.

관련 문제