Sunday, August 01, 2010

Using HTTP Response Filter in ASP.NET

In an ASP.NET application if you want to manipulate the HTML code after it has been rendered but before it is being sent back to the client, you can use a custom filter to intercept that stream and modify it according to your needs.

One scenario is injecting elements that in turn can be used by the browser in conjunction with a CSS to modify the visual appearance. Not in all cases you have access to the source code for the pages.

To demonstrate how to do that I’ll use a simple PassThroughFilter that simply forwards all method calls to the original filter.

Let me show you first how you can register the filter. There are many different places, essentially everywhere where the HttpContext.Response object is accessible. Throughout the processing of a request there are multiple events that you can use to plug in your filter. You can find a list of those events in an article that describes using an HTTP Module for implementing an intercepting filter.

But you don’t have to use an HTTP Module. You can implement your filter and then register it in various places, for example in the pages OnInit(EventArgs) override:

protected override OnInit(EventArgs e) {
   Response.Filter = new PassThroughFilter(Response.Filter);
   base.OnInit(e);
}

Another option is to use the global application object for the registration (:

public class MvcApplication : HttpApplication {
   protected void Application_Start() {
      AreaRegistration.RegisterAllAreas();
      RegisterRoutes(RouteTable.Routes);
   }

   protected void Application_BeginRequest() {
      Response.Filter = new PassThroughFilter(Response.Filter);
   }

   private static void RegisterRoutes(RouteCollection routes) {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

      routes.MapRoute(
          "Default", // Route name
          "{controller}/{action}/{id}", // URL with parameters
          new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
      );

   }
}

In this example I’m showing this in an MVC 2 based application but the same works for a WebForms based application, too.

Where you intercept depends on your specific requirements. Once you have the basic interception in place you can manipulate the HTML stream before it is sent back to the client.

So here is the full source code for the PassThroughFilter class. Happy Coding!

using System.IO;

namespace WebPortal {
   internal class PassThroughFilter : Stream {
      public PassThroughFilter(Stream originalFilter) {
         _originalFilter = originalFilter;
      }

      #region Overrides of Stream

      public override void Flush() {
         _originalFilter.Flush();
      }

      public override long Seek(long offset, SeekOrigin origin) {
         return _originalFilter.Seek(offset, origin);
      }

      public override void SetLength(long value) {
         _originalFilter.SetLength(value);
      }

      public override int Read(byte[] buffer, int offset, int count) {
         return _originalFilter.Read(buffer, offset, count);
      }

      public override void Write(byte[] buffer, int offset, int count) {
         _originalFilter.Write(buffer, offset, count);
      }

      public override bool CanRead {
         get { return _originalFilter.CanRead; }
      }

      public override bool CanSeek {
         get { return _originalFilter.CanSeek; }
      }

      public override bool CanWrite {
         get { return _originalFilter.CanWrite; }
      }

      public override long Length {
         get { return _originalFilter.Length; }
      }

      public override long Position {
         get { return _originalFilter.Position; }
         set { _originalFilter.Position = value; }
      }

      #endregion

      private readonly Stream _originalFilter;
   }
}

0 comments:

Post a Comment

All comments, questions and other feedback is much appreciated. Thank you!