c# - DelegatingHandler to decompress incoming requests in WebApi -
in app sending decent size packets client , receiving decent sized response, want implement compression on way , way back.
on way fine because can lean on iis's dynamic compression me, on way finding following issue.
i have delegating handler sits there decompress incoming requests: (most of code based on parts of 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 0 can read again decompressed.position = 0; var newcontent = new streamcontent(decompressed); // copy content type know how load correct formatter newcontent.headers.contenttype = compressedcontent.headers.contenttype; return newcontent; } } } public class deflatecompressor : compressor { private const string deflateencoding = "deflate"; public override string encodingtype { { 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 { { 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); } }
the decompression works fine , have request.content populated result decompressed json.
when pass off base.sendasync , hits controller method, model null, whereas before implemented compression working great.
i have read when read content stream coming in once off thing, thought setting request.content decompressed result should let read again?
i resolved this.
it error in httpclient implementation had moved using postasjsonasync postasync compression client side, had not added content-type header specify application/json.
after doing in client, working planned.
Comments
Post a Comment