locked
How to get length in bytes of page sent back to client by http request (I need this done in my HTTPModule) RRS feed

  • Question

  • User8809227 posted

    Hi,

    First of all, I am new to ASP.NET.  I want to get the byte count of the content sent back to the client for each http request.  The reason for this is that we are not using IIS Web Log files for Web Logging so I have to write an HTTPModule for this task.  I am using VB.NET with Visual Studio 2003 .  I have almost all of this HTTPModule working to track and log the necessary stuff.

    I cannot figure out how to get content length so I can track download bandwidth (bytes downloaded by a request) like IIS Web Logging does.  Does anyone know how to accomplish this?  If so, can you please provide details and code. 

     

    Thanks.

    Friday, December 8, 2006 4:03 PM

Answers

  • User-158764254 posted

    Expanding on ricks thought, here is a quick attempt at creating a filter

    First we need a custom stream object that can be plugged in as a filter

    'this stream acts like a decorator and defers the bulk of the work to the stream that it wraps
    Public Class TransparentStream
        Inherits System.IO.Stream
        Private _innerStream As System.IO.Stream
        Private _bytesWritten As Long = 0
    
        Public Sub New(ByVal value As System.IO.Stream)
            _innerStream = value
        End Sub
    
        Public ReadOnly Property BytesWritten() As Long
            Get
                Return _bytesWritten
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanRead() As Boolean
            Get
                Return _innerStream.CanRead
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanSeek() As Boolean
            Get
                Return _innerStream.CanSeek
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanWrite() As Boolean
            Get
                Return _innerStream.CanWrite
            End Get
        End Property
    
        Public Overrides Sub Flush()
            _innerStream.Flush()
        End Sub
    
        Public Overrides ReadOnly Property Length() As Long
            Get
                Return _innerStream.Length
            End Get
        End Property
    
        Public Overrides Property Position() As Long
            Get
                Return _innerStream.Position
            End Get
            Set(ByVal value As Long)
                _innerStream.Position = value
            End Set
        End Property
    
        Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
            _innerStream.Read(buffer, offset, count)
        End Function
    
        Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
            _innerStream.Seek(offset, origin)
        End Function
    
        Public Overrides Sub SetLength(ByVal value As Long)
            _innerStream.SetLength(value)
        End Sub
    
        Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
            'here is where our stream decorator does its actual work.
            _bytesWritten += count '<--- this is all were interested in
            _innerStream.Write(buffer, offset, count)
        End Sub
    End Class

    Then we can add our filter in an httphandler to "watch" how many bytes get written.

    Public Class Logger
        Implements IHttpModule
        Private streamWatcher As TransparentStream
    
        Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
            AddHandler context.BeginRequest, AddressOf BeginRequest
            AddHandler context.EndRequest, AddressOf EndRequest
        End Sub
        Private Sub BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
            Dim app As HttpApplication = DirectCast(sender, HttpApplication)
            streamWatcher = New TransparentStream(app.Response.Filter)
            app.Response.Filter = streamWatcher
        End Sub
    
        Private Sub EndRequest(ByVal sender As Object, ByVal e As EventArgs)
    
            'now we can see the number of bytes written to the response stream
            Dim x As Long = streamWatcher.BytesWritten
    
            If Not streamWatcher Is Nothing Then streamWatcher.Close()
        End Sub
    
        Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
        End Sub
    
    End Class
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, December 10, 2006 1:55 PM

All replies

  • User1622957740 posted

    You could use an ResponseFilter to intercept the OutputStream operations which gives you the hooks needed to count bytes... Some overhead in that though that might not be worth it.

    I just took a quick look too to see if you can get at the OutputStream and get it's lenght but it looks like that's unfortunately not accessible in any post handler execution events.

    +++ Rick ---

    Saturday, December 9, 2006 9:20 PM
  • User-158764254 posted

    Expanding on ricks thought, here is a quick attempt at creating a filter

    First we need a custom stream object that can be plugged in as a filter

    'this stream acts like a decorator and defers the bulk of the work to the stream that it wraps
    Public Class TransparentStream
        Inherits System.IO.Stream
        Private _innerStream As System.IO.Stream
        Private _bytesWritten As Long = 0
    
        Public Sub New(ByVal value As System.IO.Stream)
            _innerStream = value
        End Sub
    
        Public ReadOnly Property BytesWritten() As Long
            Get
                Return _bytesWritten
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanRead() As Boolean
            Get
                Return _innerStream.CanRead
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanSeek() As Boolean
            Get
                Return _innerStream.CanSeek
            End Get
        End Property
    
        Public Overrides ReadOnly Property CanWrite() As Boolean
            Get
                Return _innerStream.CanWrite
            End Get
        End Property
    
        Public Overrides Sub Flush()
            _innerStream.Flush()
        End Sub
    
        Public Overrides ReadOnly Property Length() As Long
            Get
                Return _innerStream.Length
            End Get
        End Property
    
        Public Overrides Property Position() As Long
            Get
                Return _innerStream.Position
            End Get
            Set(ByVal value As Long)
                _innerStream.Position = value
            End Set
        End Property
    
        Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
            _innerStream.Read(buffer, offset, count)
        End Function
    
        Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
            _innerStream.Seek(offset, origin)
        End Function
    
        Public Overrides Sub SetLength(ByVal value As Long)
            _innerStream.SetLength(value)
        End Sub
    
        Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
            'here is where our stream decorator does its actual work.
            _bytesWritten += count '<--- this is all were interested in
            _innerStream.Write(buffer, offset, count)
        End Sub
    End Class

    Then we can add our filter in an httphandler to "watch" how many bytes get written.

    Public Class Logger
        Implements IHttpModule
        Private streamWatcher As TransparentStream
    
        Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
            AddHandler context.BeginRequest, AddressOf BeginRequest
            AddHandler context.EndRequest, AddressOf EndRequest
        End Sub
        Private Sub BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
            Dim app As HttpApplication = DirectCast(sender, HttpApplication)
            streamWatcher = New TransparentStream(app.Response.Filter)
            app.Response.Filter = streamWatcher
        End Sub
    
        Private Sub EndRequest(ByVal sender As Object, ByVal e As EventArgs)
    
            'now we can see the number of bytes written to the response stream
            Dim x As Long = streamWatcher.BytesWritten
    
            If Not streamWatcher Is Nothing Then streamWatcher.Close()
        End Sub
    
        Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
        End Sub
    
    End Class
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, December 10, 2006 1:55 PM
  • User8809227 posted
    Thank you very much for the code sample.  It seems to be working as I need it to.
    Monday, December 11, 2006 10:53 AM