C#学习教程:如何启用.Netweb-API以接受g-zipedpostpublicclassLogsController:ApiController{publicHttpResponseMessagePostLog(Listlogs){if(logs!=null&&logs.Any()){vargoodLogs=newList();varbadLogs=new列表();foreach(varlogDtoinlogs){if(logDto.IsValid()){goodLogs.Add(logDto.ToLog());}else{badLogs.Add(logDto.ToLogBad());}}if(goodLogs.Any()){_logsRepo.Save(goodLogs);}if(badLogs.Any()){_logsBadRepo.Save(badLogs);}}返回新的HttpResponseMessage(HttpStatusCode.OK);这一切都很好,我有能够发送日志的设备,它运行良好。但是现在我们开始担心要传输的数据的大小,我们想看看接受一个用GZIP压缩的帖子?我应该怎么办?它是在IIS中设置的还是我可以使用ActionFilters?编辑1根据Philip的回答,我的想法是我需要在请求到达我的控制器之前拦截请求的处理。如果我可以在webapi框架尝试将请求的主体解析为我的业务对象之前捕获请求,那么这将失败,因为请求的主体仍然是压缩的。然后我可以解压缩请求的主体,并将请求传回处理链,希望WebApi框架能够将(解压缩的)主体解析为我的业务对象。看起来使用DelagatingHandler是可行的方法。它允许我在处理期间访问请求,但在我的控制器之前。所以我试了下面这个?request.Content=newDeCompressedContent(request.Content,encodingType);返回base.SendAsync(request,cancellationToken);}}publicclassDeCompressedContent:HttpContent{privateHttpContentoriginalContent;私有字符串编码类型;publicDeCompressedContent(HttpContentcontent,stringencodType){originalContent=content;编码类型=编码类型;}protectedoverrideboolTryComputeLength(outlonglength){length=-1;返回假;}protectedoverrideTaskCreateContentReadStreamAsync(){返回base.CreateContentReadStreamAsync();}protectedoverrideTaskSerializeToStreamAsync(Streamstream,TransportContextcontext){StreamcompressedStream=null;如果(编码dingType=="gzip"){compressedStream=newGZipStream(stream,CompressionMode.Decompress,leaveOpen:true);}returnoriginalContent.CopyToAsync(compressedStream).ContinueWith(tsk=>{if(compressedStream!=null){compressedStream.Dispose();}});这似乎在我的控制器中工作正常,并在调用DecompressedContent的构造函数之前调用SendAsync方法。但是SerializeToStreamAsync从未被调用,所以我添加了CreateContentReadStreamAsync以查看是否应该进行解压缩,但也没有被调用。我觉得我离解决方案很近了,但只需要一点额外的东西就可以了。我有同样的要求将压缩数据发送到.NETwebapi控制器。我提出了这个解决方案:publicclassGZipToJsonHandler:DelegatingHandler{protectedoverrideTaskSendAsync(HttpRequestMessagerequest,CancellationTokencancellationToken){//Handleonlyifcontenttypeis'application/gzip'if(request.Content.Headers.ContentType==null||request.Content.Headers.ContentType.MediaType!="application/gzip"){returnbase.SendAsync(request,cancellationToken);}//读入输入流,然后解压到输出流。//异步执行此操作,但此时并不真正需要//因为我们最终会在这之后立即等待它。流outputStream=newMemoryStream();任务task=request.Content.ReadAsStreamAsync().ContinueWith(t=>{StreaminputStream=t.Result;vargzipStream=newGZipStream(inputStream,CompressionMode.Decompress);gzipStream.CopyTo(outputStream);gzipStream.Dispose();outputStream.Seek(0,SeekOrigin.Begin);});//等待输入流和解压完成。将会很好//不要在这里阻塞并在准备就绪时异步工作,但我无法//弄清楚如何在DelegatingHandler的上下文中执行此操作。任务.等待();//下一节是关键...//保存原始内容HttpContentorigContent=request.Content;//用新解压的流替换请求内容request.Content=newStreamContent(outputStream);//将原始内容中的所有标题复制到新内容中}//将原始内容类型替换为内容类型//解压后的数据。在我们的例子中,我们可以假设application/json。//更通用和可重用的处理程序需要一些其他//方法来区分解压缩的内容类型。request.Content.Headers.Remove("内容类型");request.Content.Headers.Add("Content-Type","application/json");返回base.SendAsync(request,cancellationToken);}}使用这种方法,现在有的控制器(通常使用JSONcontentandautomaticmodelbinding)继续工作而没有任何变化我不确定为什么其他答案被接受了。它提供处理响应(这很常见)但不处理请求(这不常见)的解决方案。Accept-Encoding标头用于指定可接受的响应编码,与请求编码无关。我相信正确的答案是Kaliatech的,我有足够的声誉点数来留下这个评论并投票给他,因为我认为他基本上是正确的。但是,我的情况需要查看编码类型而不是内容类型。使用这种方法,调用系统仍然可以在content-type中指定content-type是json/xml/etc,但指定数据使用gzip或可能的其他编码/压缩机制进行编码。这使我不必在解码输入后更改内容类型,并允许任何内容类型信息以其原始状态流过。这是代码。同样,其中99%是Kaliatech的回答,包括评论,所以如果他的帖子有用,请点赞。公共类CompressedRequestHandler:DelegatingHandler{protectedoverrideSystem.Threading.Tasks.TaskSendAsync(HttpRequestMessagerequest,System.Threading.CancellationTokencancellationToken){if(IsRequetCompressed(request)){request.Content=DecompressRequestContent(request);}returnbase.SendAsync(request,cancellationToken);}privateboolIsRequetCompressed(HttpRequestMessagerequest){if(request.Content.Headers.ContentEncoding!=null&&request.Content.Headers.ContentEncoding.Contains("gzip")){返回真;}返回假;}privateHttpContentDecompressRequestContent(HttpRequestMessagerequest){//读取输入流,然后解压到输出流。//异步执行此操作,但此时并不真正需要//因为我们最终会在这之后立即等待它。流outputStream=newMemoryStream();任务task=request.Content.ReadAsStreamAsync().ContinueWith(t=>{StreaminputStream=t.Result;vargzipStream=newGZipStream(inputStream,CompressionMode.Decompress);gzipStream.CopyTo(outputStream);gzipStream.Dispose();outputStream.Seek(0,SeekOrigin.Begin);});//等待输入流和解压完成。//如果不在此处阻塞并在准备就绪时异步工作会很好,但我无法//弄清楚如何在DelegatingHandler的上下文中执行此操作。任务。等待();//保存原始内容HttpContentorigContent=request.Content;//用新解压的流替换请求内容HttpContentnewContent=newStreamContent(outputStream);//将所有标题从原始内容复制到新的foreach(varheaderinorigContent.Headers){newContent.Headers.Add(header.Key,header.Value);}返回新内容;然后我在全球范围内注册了处理程序,如果您容易受到DoS攻击,这可能是一个冒险的提议,但我们的服务已锁定,因此它适用于我们GlobalConfiguration.Configuration.MessageHandlers.Add(newCompressedRequestHandler());虽然WebAPI不支持开箱即用的Accept-Encoding标头,但Kiran有一篇文章介绍如何做到这一点Dot的博客文章-http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx-如果你实施他的解决方案,请使用自定义MessageHandler,所有你需要做的是使用Accept-Encoding:gzip或Accept-Encoding:deflate标头发出请求,WebAPI响应将在消息处理程序中为您压缩试试上面的C#学习教程:Howtoenable.Netweb-APItoacceptallthecontentsharedbyg-zipedpost。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注——publicclassDeCompressedContent:HttpContent{privateHttpContentoriginalContent;私有字符串编码类型;///////////////publicDeCompressedContent(HttpContentcontent,stringencodingType){if(content==null)thrownewArgumentNullException("content");}如果(string.IsNullOrWhiteSpace(encodingType))抛出新的ArgumentNullException("encodingType");this.originalContent=内容;this.encodingType=encodingType.ToLowerInvariant();if(!this.encodingType.Equals("gzip",StringComparison.CurrentCultureIgnoreCase)&&!this.encodingType.Equals("deflate",StringComparison.CurrentCultureIgnoreCase)){thrownewInvalidOperationException(string.Format("编码{0}不是支持。仅支持gzip或deflate编码",this.encodingType));}foreach(KeyValuePair>headerinoriginalContent.Headers){this.Headers.TryAddWithoutValidation(header.Key,header.Value);}this.Headers.ContentEncoding.Add(this.encodingType);}//////////////////protectedoverrideTaskSerializeToStreamAsync(Streamstream,TransportContextcontext){varoutput=newMemoryStream();returnthis.originalContent.CopyToAsync(output).ContinueWith(task=>{//开始output.Seek(0,SeekOrigin.Begin);if(this.encodingType.Equals("gzip",StringComparison.CurrentCultureIgnoreCase)){使用(vardec=newGZipStream(output,CompressionMode.Decompress)){dec.CopyTo(stream);}}else{使用(vardef=newDeflateStream(output,CompressionMode.Decompress)){def.CopyTo(stream);}}if(output!=null)output.Dispose();});}///////////////protectedoverrideboolTryComputeLength(outlonglength){length=-1;返回(假);}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
