سؤال

I have web application that in some pages I use Ms Ajax (Script Manager,Update Panel,...). In these pages I can't use compression because it conflicts with *.axd files.

How I can compress specific pages in my web application?

هل كانت مفيدة؟

المحلول

I use a Http module to handle my compression. I am unable to use the new IIS compression for one of my sites since it is on shared hosting and they have not enabled IIS compression. I also have a custom web.config section in which i can exclude specific file paths as in:

If you want the code for module let me know. I can post it too. One class actually does the compression while i use 3 other classes to handle the custom web.config section.

  <RiderDesign>
    <HttpCompressionSettings compressionOn="true">
      <includedFileTypes>
        <add value="text/html"/>
        <add value="text/xhtml"/>
      </includedFileTypes>
      <excludedFilePaths>
        <add value="~/demos/partialpageupdates.aspx"/>
        <add value="~/demos/inlinetextedit.aspx"/>
      </excludedFilePaths>
    </HttpCompressionSettings
 </RiderDesign>

Just specify the pages to be excluded and they are not compressed.

My compression module is below:

Imports System.Web
Imports System.IO
Imports System.Net
Imports System.IO.Compression

Namespace RiderDesign.FrameworkV4.HttpModule

    Public NotInheritable Class HttpCompressionModule
        Implements IHttpModule
        Private Shared GZIP As String = "gzip"
        Private Shared DEFLATE As String = "deflate"

        Private Shared ENCODING_TYPE As String = "encodingType"
        Private Shared CONTENT_TYPE As String = "contentType"
        Private MARK As String = "passedModule"
        Dim HttpState As HttpCompressionConfigStateModule
        Sub Dispose() Implements IHttpModule.Dispose
        End Sub
        Sub Init(ByVal context As HttpApplication) Implements IHttpModule.Init

            If HttpCompressionConfigModule.GetConfig().CompressionOn = True Then
                ' Use for any other then WebResource
                AddHandler context.PostReleaseRequestState, AddressOf context_PostReleaseRequestState
            End If

            If HttpCompressionConfigModule.GetConfig().CompressionOn = True Then
                ' Use only for WebResource.axd files
                AddHandler context.BeginRequest, AddressOf context_BeginRequest
                AddHandler context.EndRequest, AddressOf context_EndRequest
            End If
        End Sub 'IHttpModule.Init

        Sub context_PostReleaseRequestState(ByVal sender As Object, ByVal e As EventArgs)
            Dim app As HttpApplication = CType(sender, HttpApplication) '

            If TypeOf app.Context.CurrentHandler Is System.Web.UI.Page And app.Request("HTTP_X_MICROSOFTAJAX") Is Nothing Then
                Dim FilePath As String
                Dim FilePaths As List(Of String) = New List(Of String)

                For Each Me.HttpState In HttpCompressionConfigModule.GetConfig().ExcludedFilePaths
                    FilePaths.Add(String.Format("{0}", HttpState.Value))
                Next HttpState
                FilePath = String.Join(", ", FilePaths.ToArray())

                Dim ContentTypes As String
                Dim FileTypes As List(Of String) = New List(Of String)
                Dim state As HttpCompressionConfigStateModule
                For Each state In HttpCompressionConfigModule.GetConfig().IncludedFileTypes
                    FileTypes.Add(String.Format("{0}", state.Value))
                Next state
                ContentTypes = String.Join(", ", FileTypes.ToArray())


                ' Check if the path is not excluded.
                If FilePath.Contains(app.Request.AppRelativeCurrentExecutionFilePath) Then
                    Return
                End If
                ' Check if the mime type is not excluded. (Use to exclude pages that generate specific mime type (such image or Excel...))
                If Not ContentTypes.Contains(app.Response.ContentType) Then
                    Return
                End If
                ' Check if GZIP is supported by the client
                If IsGzipEncodingSupported() Then
                    app.Response.Filter = New GZipStream(app.Response.Filter, CompressionMode.Compress)
                    SetEncodingType(GZIP)
                    ' Check if DEFLATE is supported by the client 

                Else
                    If IsDeflateEncodingSupported() Then
                        app.Response.Filter = New DeflateStream(app.Response.Filter, CompressionMode.Compress)
                        SetEncodingType(DEFLATE)
                    End If
                End If
            End If
        End Sub


        Sub context_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
            Dim app As HttpApplication = CType(sender, HttpApplication) '
            '
            ' Check if the current request is WebResource.axd
            If app.Request.Path.Contains("WebResource.axd") Then
                SetCachingHeaders(app)

                If app.Context.Request.QueryString(MARK) Is Nothing Then
                    app.CompleteRequest()
                End If
            End If
        End Sub 'context_BeginRequest



        Sub context_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
            Dim app As HttpApplication = CType(sender, HttpApplication) '

            If app.Request.Path.Contains("WebResource.axd") And app.Context.Request.QueryString(MARK) Is Nothing Then
                Dim cacheKey As String = app.Request.QueryString.ToString()

                If app.Application(cacheKey) Is Nothing Then
                    CompressedIntoCache(app, cacheKey)
                End If

                SetEncodingType(CStr(app.Application((cacheKey + ENCODING_TYPE))))
                app.Context.Response.ContentType = CStr(app.Application((cacheKey + CONTENT_TYPE)))
                app.Context.Response.BinaryWrite(CType(app.Application(cacheKey), Byte()))
            End If
        End Sub 'context_EndRequest



        Private Sub CompressedIntoCache(ByVal app As HttpApplication, ByVal cacheKey As String)
            'Mark the current request by adding QueryString parameter.
            Dim request As HttpWebRequest = CType(WebRequest.Create((app.Context.Request.Url.OriginalString + "&" + MARK + "=1")), HttpWebRequest)
            request.Credentials = CredentialCache.DefaultNetworkCredentials
            Using response As HttpWebResponse = CType(request.GetResponse, HttpWebResponse)

                If (True) Then
                    ' We getting the response stream, that raise again the 'BeginRequest' event (that why we marked the request)
                    Dim responseStream As Stream = response.GetResponseStream()

                    Dim contentType As String = response.ContentType.ToLower()

                    ' Not a javascript or css content.
                    ' We compress only WebResources that are Javascript or css file.
                    ' The problem is, that we can know the content type only after we got the response. TODO: find a better solution
                    ' for non CSS or JS content
                    If Not IsContentSupported(contentType) Then
                        ' Set the response type
                        app.Context.Response.ContentType = contentType

                        ' Send the file to the client without compression
                        StreamCopy(responseStream, app.Response.OutputStream)
                        responseStream.Dispose()
                        app.Context.Response.End()
                        Return
                    End If

                    ' Copy the response stream into memory stream, so we can convert it into byte[] easly.
                    Dim dataStream As New MemoryStream()
                    StreamCopy(responseStream, dataStream)
                    responseStream.Dispose()

                    ' Convert the response into byte[]
                    Dim data As Byte() = dataStream.ToArray()
                    dataStream.Dispose()
                    Dim encodingType As String = String.Empty

                    Using memstream As MemoryStream = New MemoryStream
                        Dim compress As Stream = Nothing

                        ' Choose the compression type and make the compression
                        If IsGzipEncodingSupported() Then
                            compress = New GZipStream(memstream, CompressionMode.Compress)
                            encodingType = GZIP
                        Else
                            If IsDeflateEncodingSupported() Then
                                compress = New DeflateStream(memstream, CompressionMode.Compress)
                                encodingType = DEFLATE
                            End If
                        End If
                        compress.Write(data, 0, data.Length)
                        compress.Dispose()

                        app.Application.Lock()
                        app.Application.Add(cacheKey, memstream.ToArray())
                        app.Application.Add(cacheKey + ENCODING_TYPE, encodingType)
                        app.Application.Add(cacheKey + CONTENT_TYPE, response.ContentType)
                        app.Application.UnLock()

                    End Using
                End If
            End Using

        End Sub 'CompressedIntoCache




        Private Shared Sub StreamCopy(ByVal input As Stream, ByVal output As Stream)
            Dim buffer(2048) As Byte
            Dim read As Integer
            Do
                read = input.Read(buffer, 0, buffer.Length)
                output.Write(buffer, 0, read)
            Loop While read > 0
        End Sub 'StreamCopy

        Private Shared Sub SetCachingHeaders(ByVal app As HttpApplication)
            Dim etag As String = """" + app.Context.Request.QueryString.ToString().GetHashCode().ToString() + """"
            Dim incomingEtag As String = app.Request.Headers("If-None-Match")

            app.Response.Cache.VaryByHeaders("Accept-Encoding") = True
            app.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(365))
            app.Response.Cache.SetCacheability(HttpCacheability.Public)
            app.Response.Cache.SetLastModified(DateTime.Now.ToUniversalTime().AddDays(-1))
            app.Response.Cache.SetETag(etag)

            If [String].Compare(incomingEtag, etag) = 0 Then
                app.Response.StatusCode = CInt(HttpStatusCode.NotModified)
                app.Response.End()
            End If
        End Sub 'SetCachingHeaders


        Private Shared Function IsBrowserSupported() As Boolean
            ' Because bug in Internet Explorer 6
            Return Not (HttpContext.Current.Request.UserAgent Is Nothing Or HttpContext.Current.Request.UserAgent.Contains("MSIE 6"))
        End Function 'IsBrowserSupported


        Private Shared Function IsEncodingSupported() As Boolean
            Return IsGzipEncodingSupported() Or IsDeflateEncodingSupported()
        End Function 'IsEncodingSupported

        Private Shared Function IsGzipEncodingSupported() As Boolean
            Return Not (HttpContext.Current.Request.Headers("Accept-encoding") Is Nothing) And HttpContext.Current.Request.Headers("Accept-encoding").Contains(GZIP)
        End Function 'IsGzipEncodingSupported

        Private Shared Function IsDeflateEncodingSupported() As Boolean
            Return Not (HttpContext.Current.Request.Headers("Accept-encoding") Is Nothing) And HttpContext.Current.Request.Headers("Accept-encoding").Contains(DEFLATE)
        End Function 'IsDeflateEncodingSupported

        Private Shared Sub SetEncodingType(ByVal encoding As String)
            HttpContext.Current.Response.AppendHeader("Content-encoding", encoding)
        End Sub 'SetEncodingType

        Private Shared Function IsContentSupported(ByVal contentType As String) As Boolean
            If contentType.Contains("text/css") Or contentType.Contains("javascript") Then
                Return True
            End If
            Return False
        End Function
    End Class
End Namespace

نصائح أخرى

Have you tried HTTP compression (either dynamic and/or static content) via IIS 7, that will compress all the data that is communicated between the client and the server.

http://technet.microsoft.com/en-us/library/cc771003%28WS.10%29.aspx

I would personally use an HTTP module to compress .axd files.

There is an example of one here...

http://www.codeproject.com/KB/aspnet/httpcompression.aspx

this is may be useful for you this accepts deflate and gzip compression

  void Application_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        HttpApplication app = sender as HttpApplication;
        string acceptEncoding = app.Request.Headers["Accept-Encoding"];
        Stream prevUncompressedStream = app.Response.Filter;

        if (!(app.Context.CurrentHandler is System.Web.UI.Page ||
            app.Context.CurrentHandler.GetType().Name == "SyncSessionlessHandler") ||
            app.Request["HTTP_X_MICROSOFTAJAX"] != null)
            return;

        if (acceptEncoding == null || acceptEncoding.Length == 0)
            return;

        acceptEncoding = acceptEncoding.ToLower();

        if (acceptEncoding.Contains("deflate") || acceptEncoding == "*")
        {
            // deflate
            app.Response.Filter = new DeflateStream(prevUncompressedStream,
                CompressionMode.Compress);
            app.Response.AppendHeader("Content-Encoding", "deflate");
        }
        else if (acceptEncoding.Contains("gzip"))
        {
            // gzip
            app.Response.Filter = new GZipStream(prevUncompressedStream,
                CompressionMode.Compress);
            app.Response.AppendHeader("Content-Encoding", "gzip");
        }
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top