Compression and decompression for WebAPI performance optimization and webapi Performance Optimization
Sometimes we use compression and decompression to Improve the Performance of webapis and reduce the response time. Currently, most client browsers provide built-in decompression support. When the resources requested by the WebAPI are larger, compression is more effective for performance improvement. When the requested resources are small, compression and decompression are not required, because compression and decompression also take some time.
I saw a foreigner write an ASP. NET Web API GZip compression ActionFilter with 8 lines of code
To be honest, I was attracted by this title. After eight lines of code implementing the GZip compression filter, I tried it according to him and found that Chinese characters were garbled.
Follow his implementation method:
1. Download The DotNetZipLib Library
2. decompress the package and add the dll reference of Ionic. Zlib. dll.
3. New DeflateCompression features and GZipCompression features represent Deflate compression and GZip compression respectively. The implementation code of these two compression methods is similar.
The difference is that
ActContext. Response. Content. Headers. Add ("Content-encoding", "gzip ");
ActContext. Response. Content. Headers. Add ("Content-encoding", "deflate ");
And
var compressor = new DeflateStream( output, CompressionMode.Compress, CompressionLevel.BestSpeed)
var compressor = new GZipStream( output, CompressionMode.Compress, CompressionLevel.BestSpeed)
using System.Net.Http;using System.Web.Http.Filters;namespace WebAPI.Filter{ public class GZipCompressionAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actContext) { var content = actContext.Response.Content; var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result; var zlibbedContent = bytes == null ? new byte[0] : CompressionHelper.GZipByte(bytes); actContext.Response.Content = new ByteArrayContent(zlibbedContent); actContext.Response.Content.Headers.Remove("Content-Type"); actContext.Response.Content.Headers.Add("Content-encoding", "gzip"); actContext.Response.Content.Headers.Add("Content-Type", "application/json"); base.OnActionExecuted(actContext); } }}using System.Net.Http;using System.Web.Http.Filters;namespace WebAPI.Filter{ public class DeflateCompressionAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actContext) { var content = actContext.Response.Content; var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result; var zlibbedContent = bytes == null ? new byte[0] : CompressionHelper.DeflateByte(bytes); actContext.Response.Content = new ByteArrayContent(zlibbedContent); actContext.Response.Content.Headers.Remove("Content-Type"); actContext.Response.Content.Headers.Add("Content-encoding", "deflate"); actContext.Response.Content.Headers.Add("Content-Type", "application/json"); base.OnActionExecuted(actContext); } }
4. Add a compression help class CompressionHelper
using System.IO;using Ionic.Zlib;namespace WebAPI.Filter{ public class CompressionHelper { public static byte[] DeflateByte(byte[] str) { if (str == null) { return null; } using (var output = new MemoryStream()) { using ( var compressor = new DeflateStream( output, CompressionMode.Compress, CompressionLevel.BestSpeed)) { compressor.Write(str, 0, str.Length); } return output.ToArray(); } } public static byte[] GZipByte(byte[] str) { if (str == null) { return null; } using (var output = new MemoryStream()) { using ( var compressor = new GZipStream( output, CompressionMode.Compress, CompressionLevel.BestSpeed)) { compressor.Write(str, 0, str.Length); } return output.ToArray(); } } }}
5. Controller call. Here I write the test code:
Public class TestController: ApiController {StringBuilder sb = new StringBuilder (); [GZipCompression] public string Get (int id) {for (int I = 0; I <1000; I ++) {sb. append ("here is the territory of China" + I);} return sb. toString () + DateTime. now. toLocalTime () + "," + id ;}}
First, do not use compression. Note // [GZipCompression] Mark. The file size is 26.4kb and the request time is 1.27 s.
Use the [GZipCompression] Mark. After compression is added, the file size is 2.4kb, the response time is 1.21, And the Respouse Body is much smaller, but the response time is not obvious, because the download speed is too fast in the local environment, it takes a certain amount of time to compress and decompress the package, and the loading time of the interface is mainly consumed on onload. There is a problem: Chinese characters are garbled.
Using the Compression provided by. net, the corresponding class libraries-GZipStream and DeflateStream are provided in System. IO. Compression. The Controller call code remains unchanged. Create a CompressContentAttribute. cs class. The Code is as follows:
Using System. web; using System. web. http. controllers; using System. web. http. filters; namespace WebAPI. filter {// <summary> // automatically identifies whether the client supports compression, if yes, the compressed data is returned. // Attribute that can be added to controller methods to force content // to be GZip encoded if the client supports it // </summary> public class CompressContentAttribute: actionFilterAttribute {// <summary> // Override to compress the content That is generated by // an action method. /// </summary> /// <param name = "filterContext"> </param> public override void OnActionExecuting (HttpActionContext filterContext) {GZipEncodePage ();} /// <summary> /// Determines if GZip is supported /// </summary> /// <returns> </returns> public static bool IsGZipSupported () {string AcceptEncoding = HttpContext. current. request. headers ["Accept-Encoding"]; If (! String. isNullOrEmpty (AcceptEncoding) & (AcceptEncoding. contains ("gzip") | AcceptEncoding. contains ("deflate") return true; return false;} // <summary> // Sets up the current page or handler to use GZip through a Response. filter /// IMPORTANT: // You have to call this method before any output is generated! /// </Summary> public static void GZipEncodePage () {HttpResponse Response = HttpContext. current. response; if (IsGZipSupported () {string AcceptEncoding = HttpContext. current. request. headers ["Accept-Encoding"]; if (AcceptEncoding. contains ("deflate") {Response. filter = new System. IO. compression. deflateStream (Response. filter, System. IO. compression. compressionMode. compress); # region II6 does not support this method (actually This value is null by default and does not need to be removed) // Response. headers. remove ("Content-Encoding"); # endregion Response. appendHeader ("Content-Encoding", "deflate");} else {Response. filter = new System. IO. compression. GZipStream (Response. filter, System. IO. compression. compressionMode. compress); # region II6 does not support this method (in fact, this value is null by default and does not need to be removed) // Response. headers. remove ("Content-Encoding"); # endregion Response. appendHeader ("Content-Encoding ", "Gzip") ;}}// Allow proxy servers to cache encoded and unencoded versions separately Response. appendHeader ("Vary", "Content-Encoding") ;}/// <summary> /// force Defalte compression // Content-encoding: gzip, Content-Type: application/json // DEFLATE is a patent-free compression algorithm that can achieve lossless data compression and has many open-source implementation algorithms. /// </Summary> public class DeflateCompressionAttribute: ActionFilterAttribute {public override void OnActionExecuting (HttpActionContext filterContext) {HttpResponse Response = HttpContext. current. response; Response. filter = new System. IO. compression. deflateStream (Response. filter, System. IO. compression. compressionMode. compress); # region II6 does not support this method (in fact, this value is null by default and does not need to be removed) // Response. headers. remove ("Content-Encoding"); # endregion Response. appendHeader ("Content-Encoding", "deflate") ;}/// <summary> /// force GZip compression, application/json // Content-encoding: gzip, content-Type: application/json // GZIP is another compressed database that uses DEFLATE to compress data. // </summary> public class GZipCompressionAttribute: actionFilterAttribute {public override void OnActionExecuting (HttpActionContext filterContext) {HttpResponse Response = HttpContext. current. response; Response. filter = new System. IO. compression. GZipStream (Response. filter, System. IO. compression. compressionMode. compress); # region II6 does not support this method (in fact, this value is null by default and does not need to be removed) // Response. headers. remove ("Content-Encoding"); # endregion Response. appendHeader ("Content-Encoding", "gzip ");}}}View Code
Run the command to view the results. The compression capability is slightly worse than that of DotNetZipLib, but no garbled characters are found.
Change the mark in the Controller code to [DeflateCompression], and use Deflate compression to see the effect:
After Deflate compression, the Content-Length value is 2538, while the GZip compression Content-Length value is 2556. It can be seen that Deflate compression is better.
Here, the compression of WebAPI is implemented through the Action filter. Of course, you can also write it in the global configuration of WebAPI. Considering that some API interfaces do not need to be compressed, so it is implemented through the Action filter.
Dudu's article HttpClient and APS. NET Web API: compression and decompression of request content on the client and on the server.