Click here to Skip to main content
6,295,667 members and growing! (10,576 online)
Email Password   helpLost your password?
Web Development » ASP.NET » Utilities     Intermediate License: The Code Project Open License (CPOL)

ServerComponents HTTP Handlers

By Bishoy Labib

By using only configuration, create and customize HTTP handlers that do a lot of tasks.
C#.NET 2.0, ASP.NET, Architect, Dev, Design
Posted:5 Oct 2008
Views:5,019
Bookmarked:21 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
8 votes for this article.
Popularity: 3.70 Rating: 4.10 out of 5

1
1 vote, 12.5%
2
1 vote, 12.5%
3
1 vote, 12.5%
4
5 votes, 62.5%
5

Introduction 

I’m currently involved in multiple consumer focused web portals that are deployed on multiple servers with load balancing. These environments contain a unique set of challenges which includes:

  • User upload images and these images needs to be replicated to the different load balanced servers.
     
  • News articles are published in one location and needs to be read from different servers and locations with different configurations.
  • User download files that they purchased and we need to provide them with download URLs that does custom authorization before download.

I’ve done a search to find any readymade components that solve some of the above problems but found nothing. So I decided to create a component that handles HTTP requests in an ASP.NET website and dynamically do any customization of the above based on configurations only. 

Features 

By using only configuration, create and customize handlers that do a combination of the following:

  1. Authorize request using custom class.
  2. Get content from File, HTTP, FTP, or a custom class.
  3. Send the content to user via file download, or in the HTTP response.
  4. Cache the content in files or memory.
  5. Replace text in the delivered content.
  6. Redirect or Server Transfer the user to a new URL.

Use Cases 

  1. If you want to authorize a request with custom code before user downloads a file.
  2. If you have a web farm with multiple servers that have content files uploaded to one of the servers and you want users to request these files from any server. So each server checks for the file in a certain directory and if not found he tries to gets it from other servers, either using folder sharing or by downloading the file using FTP or HTTP. Example of such scenario is replicating user uploaded images or replicating news content files saved in XML, HTML or ASPX formats and even replacing text inside them to manipulate and correct URLs.
  3. If you want to emulate another HTTP server by requesting it and then writing the content from the server in the user response.
  4. If you want to redirect the users from a web server to another using the same path. Example of such scenario is when you have a new domain and you want to redirect users that enter the old domain to the new one while maintaining the same path after the domain. 

Using the Code

  1. In your website, add reference to (or put in the bin directory) the assembly ServerComponents.dll
     

  2. In web.config, add the httpHandlers configuration to tell ASP.NET that the ServerComponent.Handlers.Handler class is handling requests with specific criteria. 

      <system.web>
        <httpHandlers>
          <add path="*" verb="GET" validate="false" 
    		type="ServerComponents.Handlers.Handler"/>
        </httpHandlers>
      </system.web>

    Note: in the path="*" make sure you change this to the correct path criteria you want. You can add multiple entries to serve multiple options. Also note that this path allows you only to select certain extensions or folders, for more explanation of how to write this path check this link.

  3. In web.config add the appropriate configuration sections to configure how the handler will  behave in different conditions like the following example:

      <configSections>
        <section name="serverComponents.handlerConfiguration" 
    	type="ServerComponents.Handlers.HandlerConfiguration"/>
      </configSections>
      
      <serverComponents.handlerConfiguration>
        <handlers>
          <addHandler name="MusicFiles" regex="test/music" 
    		root="http://localhost:12697/TestingWebsite/test/music/">
            <steps>
              <addStep name="GetFromFile" type="GetFromFile" 
    			path="E:\Audio\English\"></addStep>
              <addStep name="Download" type="Download"></addStep>
            </steps>
          </addHandler>
          <addHandler name="GoogleSearch" regex="test/google" 
    		root="http://localhost:12697/TestingWebsite/test/google/">
            <steps>
              <addStep name="GetFromHTTP" type="GetFromHTTP" 
    			path="http://www.google.com/"></addStep>
              <addStep name="Replace1" type="Replace" find="google" 
    		replace="microsoft" isCaseSensitive="false"></addStep>
              <addStep name="Replace2" type="Replace" find="mail" 
    		replace="e-mail" isCaseSensitive="false"></addStep>
              <addStep name="CacheInMemory" type="CacheInMemory" seconds="300">
    		</addStep>
              <addStep name="Write" type="Write"></addStep>
            </steps>
          </addHandler>
          <addHandler name="NewsCMS" regex="test/news" 
    	root="http://localhost:12697/TestingWebsite/test/news/">
            <steps>
        <addStep name="GetFromFTP" type="GetFromFTP" 
    	path="ftp://10.0.0.10/news/" username="guest" password=""></addStep>
              <addStep name="CacheInFile" type="CacheInFile" 
    		path="G:\Projects\TestingWebsite\newscache\"></addStep>
              <addStep name="ServerTransfer" type="ServerTransfer" 
    		path="~/newscache/"></addStep>
            </steps>
          </addHandler>
        </handlers>
      </serverComponents.handlerConfiguration>

In the above example, there are three types of handlers: (note that all name attributes are just for identifying configuration elements and doesn’t affect the actual processing)

  1. MusicFiles: If URL contains test/music then get the requested file from a folder that is not accessible from normal website browsing and let the user download it.
  2. GoogleSearch: If URL contains test/google then request the query after test/google to the real google website, replace couple of words, cache the result in memory then return the result to the user as if he is browsing google from our website.
  3. NewsCMS: If URL contains test/news then get the requested news ASPX page from an FTP, cache it on a local folder for later requests, and then make a server transfer that let ASP.NET execute the page. 

Reference

This is the handler element:

<addHandler name="MyHandler" regex="test/news" 
	root="http://localhost:12697/TestingWebsite/test/news/">

It has the following attributes:

  • name: which is just for configuration element identification purposes.
  • regex: this is a regular expression that is matched against the request URL to figure which handler should be executed. If more than one handler regex match the URL, the first match will be executed.
  • root: this is the root of the handler URL, everything in the URL after this root is considered the relative path of the requested file and is appended to any handler step that has a path attribute. 

Here is the full set of steps that can be added inside a handler: 

<addHandler name="MyHandler" regex="test/news" 
	root="http://localhost:12697/TestingWebsite/test/news/">
   <steps>
     <addStep name="CustomAuthorize" type="CustomAuthorize" 
	path="MyNamespace.MyClass"></addStep>
     <addStep name="GetFromFile" type="GetFromFile" 
	path="E:\Audio\English\"></addStep>
     <addStep name="GetFromHTTP" type="GetFromHTTP" 
	path="http://www.google.com/"></addStep>
     <addStep name="GetFromFTP" type="GetFromFTP" 
	path="ftp://10.0.0.10/news/" username="guest" password=""></addStep>
     <addStep name="GetFromClass" type="GetFromClass" 
	path="MyNamespace.MyClass"></addStep>
     <addStep name="Replace" type="Replace" 
	find=http://localhost/OldUrl/ 
	replace=http://localhost:12697/TestingWebsite/ 
	isCaseSensitive="false"></addStep>
     <addStep name="CacheInFile" type="CacheInFile" 
	path="G:\Projects\TestingWebsite\newscache\"></addStep>
     <addStep name="CacheInMemory" type="CacheInMemory" seconds="300"></addStep>
     <addStep name="Download" type="Download"></addStep>
     <addStep name="Write" type="Write"></addStep>
     <addStep name="ServerTransfer" type="ServerTransfer" path="~/newscache/"></addStep>
     <addStep name="Redirect" type="Redirect" path="http://www.google.com/"></addStep>
   </steps>
 </addHandler>

Steps are executed in the following order:

  1. CustomAuthorize
  2. Check if cache exists (and if exists we continue from 6)
  3. All Get steps (could be more than one) are executed in order until one is successful.
  4. All Replace steps are executed in order.
  5. CacheInFile and/or CachInMemory
  6. Download or Write or ServerTransfer or Redirect

Steps are categorized by type as the following:

  • CustomAuthorize: takes a class name in the path attribute, the class should implement the ServerComponents.Handlers.ICustomAuthorizeHandler interface which takes the HttpContext and should return true if authorized.
  • GetFromFile: takes a folder path and read the file with relative path inside this folder, the relative path is retrieved from the user request URL after the handler root.
  • GetFromHTTP: takes a URL in the path attribute and make an HTTP request for this URL + the relative path, and read the content of the returned response.
  • GetFromFTP: takes an FTP URL with username and password, and read a file from the FTP with the URL + the relative path.
  • GetFromClass: takes a class name in the path attribute, the class should implement the ServerComponents.Handlers.ICustomRequestHandler interface which takes the HttpContext and should return a stream that contains the content. 
  • Replace: takes the parameters find, replace, isCaseSensitive and uses regular expressions to match and replace. So the find parameter accepts regular expressions not only normal string matches. And you can repeat this steps for as many replaces you want.
  • CacheInFile: takes a folder path in which to save cached copies of the content retrieved from any GET method. The cached copy is saved after the replace operations. And is replaced permanently until the file is manually deleted.
  • CacheInMemory: takes the duration of cache with the seconds attribute which will expire the cache after this duration.
  • Download: stream the content to the user response as a file download
  • Write: stream the content to the user response as response text
  • ServerTransfer: make a server transfer to the path + relative path. Important Note: take into consideration when using ServerTransfer that you do the transfer to a URL that is outside the httpHandlers path criteria because this will cause an infinite loop that result in an unexplained browser error.
  • Redirect: make a redirect to the path + relative path 

A handy steps shortcut

For handy shortcuts on the available steps and their parameters check and bookmark this: http://bishoylabib.blogspot.com/2008/10/servercomponents.html.

Future

Until now I only used this in testing. Honestly I didn’t test these steps: CustomAuthorize, GetFromClass, and GetFromFTP.

I plan to use this component in multiple production situations in the next couple of days. So I’ll be adding bug fixes and may be more needed features.

If you have found a bug or have a suggestion for a required feature, please tell me. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Bishoy Labib


Member
IF YOU WANT TO IMPROVE YOUR SOFTWARE, DON'T TEST MORE; DEVELOP BETTER.

http://bishoylabib.blogspot.com
Occupation: Team Leader
Company: Link Development
Location: Egypt Egypt

Other popular ASP.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 1 of 1 (Total in Forum: 1) (Refresh)FirstPrevNext
GeneralVery Neat PinmemberAlomgir Miah Abdul12:06 25 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 5 Oct 2008
Editor: Deeksha Shenoy
Copyright 2008 by Bishoy Labib
Everything else Copyright © CodeProject, 1999-2009
Web18 | Advertise on the Code Project