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: 5728

Comments & Reviews

Post a Comment
Loading...
Blog Index