Compressing Web Service Calls

Most webservers will compress data if the clients support it.

Unfortunately for .net developers the auto generated proxy classes that access webservices don’t include this functionality.

I’ll show you how to achieve this while avoiding changing any code in the auto generated proxy classes.

(These classes utilize ICSharpCode.SharpZipLib.dll so you’ll have to download this)

This following class will deal with decompressing a response.

Imports System.Net
Imports ICSharpCode.SharpZipLib

Public Class UncompressedGzipResponse
    Inherits System.Net.WebResponse

    Private cCompressedGzipResponse As HttpWebResponse

    Public Sub New(ByVal compressedGzipResponse As HttpWebResponse)
        cCompressedGzipResponse = compressedGzipResponse
    End Sub

    Public Overrides Function GetResponseStream() As System.IO.Stream

        Dim compressedStream As System.IO.Stream = New GZip.GZipInputStream(cCompressedGzipResponse.GetResponseStream)
        Dim decompressedStream As New System.IO.MemoryStream
        Dim size As Integer = 2048
        Dim writeData(2048) As Byte
        While True
            size = compressedStream.Read(writeData, 0, size)
            If size > 0 Then
                decompressedStream.Write(writeData, 0, size)
                Dim s As String = System.Text.Encoding.ASCII.GetString(writeData)
                s = s & ""
                Exit While
            End If
        End While
        decompressedStream.Seek(0, IO.SeekOrigin.Begin)

        Return CType(decompressedStream, IO.Stream)

    End Function

    Public Overrides Property ContentType() As String
            Return cCompressedGzipResponse.ContentType
        End Get
        Set(ByVal value As String)
            cCompressedGzipResponse.ContentType = value
        End Set
    End Property

    Public Overrides Property ContentLength() As Long
            Return cCompressedGzipResponse.ContentLength
        End Get
        Set(ByVal value As Long)
            cCompressedGzipResponse.ContentLength = value
        End Set
    End Property

    Public Overrides ReadOnly Property Headers() As System.Net.WebHeaderCollection
            Return cCompressedGzipResponse.Headers
        End Get
    End Property

End Class

This next class will handle most of the logic so that your proxy class can be as small as possible:

Public Class WebServiceCompressionHelper
    Public Shared Function GetWebRequest(ByVal uri As System.Uri, ByVal output As WebRequest, ByVal compress As Boolean) As WebRequest

        '*** add gzip
        If compress Then
            output.Headers.Item(Net.HttpRequestHeader.AcceptEncoding) = "gzip"
        End If

        Return output
    End Function

    Public Shared Function GetWebResponse(ByVal output As WebResponse, ByVal request As System.Net.WebRequest) As WebResponse

        Dim compressedResponse As HttpWebResponse = Nothing
        If TypeOf output Is HttpWebResponse Then
            compressedResponse = CType(output, HttpWebResponse)
        End If

        If compressedResponse IsNot Nothing AndAlso compressedResponse.ContentEncoding = "gzip" Then
            output = New UncompressedGzipResponse(compressedResponse)
        End If
        Return output
    End Function
End Class

In order to make use of this we need to tap into a few methods in the auto generated proxy.  The easiest way to do this is to extend the proxy class into your own subclass, like so:

Public Class MyService
    Protected Overrides Function GetWebRequest(ByVal uri As System.Uri) As System.Net.WebRequest
        Return Walshgroup.Webservices.Common.WebServiceCompressionHelper.GetWebRequest(uri, MyBase.GetWebRequest(uri), True)
    End Function
    Protected Overrides Function GetWebResponse(ByVal request As System.Net.WebRequest) As System.Net.WebResponse
        Dim output As System.Net.WebResponse = MyBase.GetWebResponse(request)
        Return Walshgroup.Webservices.Common.WebServiceCompressionHelper.GetWebResponse(output, request)
    End Function
End Class

Now, instead of instantiating your generated proxy class, you will simply instantiate your subclass.

That’s it!



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s