/* This file implements an HttpHandlerFactory that processes all requests for a given web application. For this to be activated you must do two things: 1) Add the following section to the httpHandlers section of the system.web section of your web.config file (it's already there actually, you just need to uncomment it): 2) Set your IIS Wildcard Mapping to :\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll. This will allow all requests that IIS doesn't know about to go to ASP.NET (for the IIS application that is) and uncheck "Verify that file exists". By doing this, you have the ability to use HttpHandlers to manage virtual paths manually via HttpHandlers storing your information in XML, a database, web.config, or whatever else rather than by creating hard virtual directories in IIS. In other words, you get a very high level of control over all your ASP.NET paths and filenames. ==Creating ASP.NET HTTP Handler Factories== The basic idea behind an HttpHandlerFactory can be seen in the Factory GoF Design Pattern. A GoF Design Pattern is a software design pattern that was written in detail in the "Gang of Four" (GoF) book. The name of the book is "Design Patterns" and it's written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, otherwise known as the "gang of four". This book is the standard textbook for object-oriented design and is arguably the most comprehensive book on the topic. The Factory design pattern is simply one of the "Creational Design Patterns" in the GoF book and is by far and away one of the most common design patterns in all of object-oriented design. The basic idea behind the factory pattern is that you have an object that accepts a request and then based on the request, the object then returns an object that will be appropriate for that particular request. For example, say you have an abstract Person class, , an SalesPerson class, a MarketingPerson class, and an ExecutivePerson class where SalesPerson, MarketingPerson, and ExecutivePerson all inherit from Person. Furthermore, say that the abstract Person class has an abstract method named "ComputeSalary" and each of the other classes implement their own implementation of "ComputeSalary". With this setup, a factory design pattern would look like this: public static class PersonFactory { public static Person CreatePerson(PersonType type) { if(type == PersonType.Sales) { return new SalesPerson( ); } else if(type == PersonType.Marketing) { return new MarketingPerson( ); } else if(type == PersonType.Executive) { return new ExecutivePerson( ); } else { throw new ArgumentOutOfRangeException("Invalid person type."); } } } PersonType type = (PersonType)inputFromExternalSource; Person p = PersonFactory.CreatePerson(type); p.ComputeSalary( ); Given the input from an external source, the "p" object will have a different implementation. Using the factory pattern we were able to have an object created for us based upon some input. This is exactly what happens with an HttpHandlerFactory. When a request is sent to an HttpHandlerFactory, the HttpHandlerFactory will do some logic and then return an instance of an HttpHandler. HttpHandlers are explained in detail in the App_Code/ServiceHttpHandler.cs file, so it would be a good idea for you to read that to understand what an HttpHandler is. Typically an HttpHandlerFactory is created by creating a class that implements the IHttpHandlerFactory. This interface requires you to implement a "GetHandler" property and a "ReleaseHandler" property. Here is an example of what you would implement: IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) { throw new Exception("The method or operation is not implemented."); } void ReleaseHandler(IHttpHandler handler) { throw new Exception("The method or operation is not implemented."); } When a request goes to the HttpHandlerFactory, the GetHandler factory will be called and it's in that method that you will do your logic to determine what HttpHandler to create and return. You can see an example of this in the implementation in this file and parts will be explained in a moment. Before, we get to that though, we need to answer one question: why am I not inheriting from PageHandlerFactory instead of implementing the IHttpHandlerFactory interface? The answer deals with what this HttpHandlerFactory is doing. This HttpHandlerFactory is used as a universal HttpHandlerFactory that accepts absolutely every request from an IIS application and routes it as necessary. By using this method, you can alias absolutely anything you want in your entire application including allows any number of resources to be accessible via path only, without ever requiring anyone to remember file names. When doing this you have do deal with not only your own HttpHandlers, but also ASP.NET's HttpHandlers. So, when I'm looking at the url they are accessing I need to make a decision whether to return my own HttpHandler or one of ASP.NET's. If the request is something one of my HttpHandlers will process, then I will return an instance of one of my own HttpHandlers, but if the request is accessing something in my code folder, which contains JavaScript documents, then I want to return an instance of DefaultHttpHandler so they are handled correctly, but when an ASPX page is accessed I can't exactly just return an instance of the ASPX HttpHandler. Why? Well, look at the web.config that ASP.NET uses. That's an HttpHandlerFactory, not an HttpHandler and the two look nothing alike. Thankfully, however, the System.Web.UI.PageHandlerFactory isn't sealed, so in my HttpHandlerFactory here I'm inheriting from it and when a request is accessed that I'm not familiar with, then I simply give the request to the base class's 'GetHandler' implementation. Other than that, an HttpHandlerFactory is one if the simplest things you can ever work with. For more information on the universal HttpHandlerFactory Technique you can read my blog entry on the subject at http://www.netfxharmonics.com/2007/03/The-Universal-HttpHandlerFactory-Technique.aspx. */ using System; using System.Web; using System.Web.UI; namespace Sample.Web.HttpExtensions { public class SampleHttpHandlerFactory : PageHandlerFactory { public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) { String uri = context.Request.Url.ToString( ).ToLower( ); if (uri.EndsWith(".jsx")) { return new JavaScriptRewriterHttpHandler( ); } if (uri.Contains("/lib/")) { return new DefaultHttpHandler( ); } if (uri.Contains("/code/")) { return new DefaultHttpHandler( ); } if (uri.Contains("/styles/")) { return new DefaultHttpHandler( ); } if (uri.Contains("/fonts/")) { return new DefaultHttpHandler( ); } if (uri.Contains("/images/")) { return new DefaultHttpHandler( ); } else if (uri.Contains("/services/")) { return new ServiceHttpHandler( ); } else { return base.GetHandler(context, requestType, url, pathTranslated); } } } }