Microsoft Web API Data Compression

Thursday, Mar 12, 2015 at 19:36

David Martin

As all developers understand performance is paramount and there is nothing worse than writing a great method that returns all this great data only to find that you need hundreds of KB's of data transfer to deliver it. Well I was really surprised that even the new MS Web API 2.2 does not include a compression function right out of the box.



The project I am working on is a long term operational web business and it was built way back then in VB so most of the code spinets and data I am going to publish will be to aid the VB developers out there. There are plenty of us still around and really at the end of the day the c# and vb languages are almost interchangeable and there are a wealth of conversion tools to switch back and forth.



So here is my VB.NET gzip class that I use to compress the data stream of response made using the Web API:



Imports System.Net.Http

Imports System.Threading

Imports System.Threading.Tasks

Imports System.IO

Imports System.IO.Compression

Imports System.Net



Namespace ITBeyond.Handlers



Public Class CompressHandler

Inherits DelegatingHandler

Protected Overrides Function SendAsync(request As HttpRequestMessage, cancellationToken As CancellationToken) As Task(Of HttpResponseMessage)

Return MyBase.SendAsync(request, cancellationToken). _

ContinueWith(Of HttpResponseMessage)( _

Function(responseToCompleteTask)

Dim response As HttpResponseMessage = responseToCompleteTask.Result

If response.RequestMessage.Headers.AcceptEncoding IsNot Nothing Then

Dim encodingType As String = response.RequestMessage.Headers.AcceptEncoding.First().Value



response.Content = New CompressedContent(response.Content, encodingType)

End If

Return response

End Function, TaskContinuationOptions.OnlyOnRanToCompletion)

End Function

End Class



Public Class CompressedContent

Inherits HttpContent

Private originalContent As HttpContent

Private encodingType As String



Public Sub New(content As HttpContent, encodingType As String)

If content Is Nothing Then

Throw New ArgumentNullException("content")

End If

If encodingType Is Nothing Then

Throw New ArgumentNullException("encodingType")

End If

originalContent = content

Me.encodingType = encodingType.ToLowerInvariant()

If Me.encodingType "deflate" Then

Throw New InvalidOperationException(String.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", Me.encodingType))

End If

Me.Headers.ContentEncoding.Add(encodingType)

End Sub



Protected Overrides Function TryComputeLength(ByRef length As Long) As Boolean

length = -1

Return False

End Function



Protected Overrides Function SerializeToStreamAsync(stream As Stream, context As TransportContext) As Task

Dim compressedStream As Stream = Nothing

If encodingType = "gzip" Then

compressedStream = New GZipStream(stream, CompressionMode.Compress, leaveOpen:=True)

ElseIf encodingType = "deflate" Then

compressedStream = New DeflateStream(stream, CompressionMode.Compress, leaveOpen:=True)

End If

Return originalContent. _

CopyToAsync(compressedStream). _

ContinueWith( _

Sub(tsk)

If compressedStream IsNot Nothing Then

compressedStream.Dispose()

End If

End Sub)

End Function

End Class



End Namespace



You can simply copy and paste this directly into a new class file (mine is called CompressHandler.vb) and load it into the Global.asax.vb or App_Start - WebApiConfig.vb file as talked about in the previous blog - Microsoft Web API, CORS, OPTIONS & Credentials via POST using:

GlobalConfiguration.Configuration.MessageHandlers.Add(New ITBeyond.Handlers.CompressHandler())



The GlobalConfiguration line above needs to go in the Application_Start of the global.asax.vb such as this:

Imports System.Web.SessionState

Imports System.Web.Http

Imports System.Web.Routing

Imports System.Net.Http

Imports System.Net



Public Class Global_asax

Inherits System.Web.HttpApplication



Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

' Fires when the application is started

GlobalConfiguration.Configuration.MessageHandlers.Add(New ITBeyond.Handlers.CompressHandler())

End Sub

.......

End Class



NOTE: The imports are important and rely on loading using Nuget the Microsoft ASP.NET Web API 2.2 Client Libraries, Core Libraries and Web Host into the project.



Once this is loaded fire up one of your Web API methods and you will see the compress headers present in the response object and the object will be much smaller due to the compression.



Good luck and I hope this helps someone out there that is most likely struggling as I was to make this work. If this is not clear or you need some more help register and provide your comments and I will try to answer your questions.
David Martin
Managing Director
Lifetime Member:My Profile  My Blog  Send Message
BlogID: 6348
Views: 5998

Comments & Reviews

Post a Comment
Loading...
Blog Index