Click here to Skip to main content
13,199,685 members (68,193 online)
Click here to Skip to main content
Add your own
alternative version


85 bookmarked
Posted 20 Apr 2007

Reverse Proxy in C# .NET v2.0

, 20 Apr 2007
Rate this:
Please Sign up or sign in to vote.
Implementing Reverse Proxy Server in C# .NET v2.0 through HTTP Handler in IIS

Screenshot - Article.gif


This article illustrates how a reverse proxy server can be developed in C# .NET v2.0 using HTTP Handler in IIS. The idea is to intercept and manipulate incoming HTTP requests to the IIS web server. I've developed a simple server with a basic, HTTP Reverse Proxy functionality, but there is still a lot more to add.


A reverse proxy differs from an ordinary forward proxy. A forward proxy is an intermediate server that accepts requests addressed to it. It then requests content from the origin server and returns it to the client. The client must be configured to use the forward proxy. The reverse proxy does not require any special configuration by the client. The client requests content from the reverse proxy. The reverse proxy then decides where to send those requests, and returns the content as if it was itself the origin. Reverse proxies can be used to bring several servers into the same URL space.

Using the code

The below code is the core of the Reverse Proxy Server. I've used a HTML parser written by Jeff Heaton for rewriting the URLs in the HTML page rendered by the Reverse Proxy Server.

Points to Ponder

  1. IHttpHandler, the abstract HTTP Handler base class of .NET must be inherited to define custom HTTP Handler.
  2. IRequiresSessionState must be inherited if we are required to manipulate session variables.
  3. IsReusable is a read-only property which can be used to define where the application instance can be pooled/reused.
 * FILE NAME    :    Program.cs
 * DATE CREATED :    March 26, 2007, 16:15:05
 * CREATED BY   :    Gunasekaran Paramesh
 * LAST UPDATED :    April 16, 2007, 3:10:09 PM
 * UPDATED BY   :    Gunasekaran Paramesh
 * DESCRIPTION  :    Implementation of Reverse Proxy Server through IIS HTTP 
                     handler in C# .NET v2.0

using System;
using System.IO;
using System.Net;
using System.Web;
using System.Text;
using System.Web.Mail;
using System.Collections;
using System.Configuration;
using System.Web.SessionState;
using System.DirectoryServices;

namespace TryHTTPHandler
public class SyncHandler : IHttpHandler, IRequiresSessionState
    public bool IsReusable { get { return true; } }

    // Process incoming request
    public void ProcessRequest(HttpContext Context)
        string ServerURL = "";            

            // Parsing incoming URL and extracting original server URL
            char[] URL_Separator = { '/' };
            string[] URL_List = Context.Request.Url.AbsoluteUri.Remove(0, 
            ServerURL = "http://" + 
                URL_List[2].Remove(URL_List[2].Length - 5, 5) + @"/";
            string URLPrefix = @"/" + URL_List[1] + @"/" + 
                URL_List[2]; // Eg. "/handler/stg2web.sync";
            for ( int i = 3; i < URL_List.Length; i++ )
                ServerURL += URL_List[i] + @"/";
            ServerURL = ServerURL.Remove(ServerURL.Length -1, 1);
            WriteLog(ServerURL + " (" + 
                Context.Request.Url.ToString() + ")");

            // Extracting POST data from incoming request
            Stream RequestStream = Context.Request.InputStream;
            byte[] PostData = new byte[Context.Request.InputStream.Length];
            RequestStream.Read(PostData, 0,
                (int) Context.Request.InputStream.Length);

            // Creating proxy web request
            HttpWebRequest ProxyRequest = (
                HttpWebRequest) WebRequest.Create(ServerURL);
            if ( ConfigurationManager.AppSettings["UpchainProxy"] == 
                "true" )
                ProxyRequest.Proxy = new WebProxy(
                    ConfigurationManager.AppSettings["Proxy"], true);

            ProxyRequest.Method = Context.Request.HttpMethod;
            ProxyRequest.UserAgent = Context.Request.UserAgent;                
            CookieContainer ProxyCookieContainer = new CookieContainer();
            ProxyRequest.CookieContainer = new CookieContainer();
                ProxyCookieContainer.GetCookies(new Uri(ServerURL)));
            ProxyRequest.KeepAlive = true;

            //For POST, write the post data extracted from the incoming request
            if ( ProxyRequest.Method == "POST" )
                ProxyRequest.ContentType = 
                ProxyRequest.ContentLength = PostData.Length;
                Stream ProxyRequestStream = ProxyRequest.GetRequestStream();
                ProxyRequestStream.Write(PostData, 0, PostData.Length);

            // Getting response from the proxy request                
            HttpWebResponse ProxyResponse = (
                HttpWebResponse) ProxyRequest.GetResponse();

            if (ProxyRequest.HaveResponse)
                // Handle cookies
                foreach(Cookie ReturnCookie in ProxyResponse.Cookies)
                    bool CookieFound = false;
                    foreach(Cookie OldCookie in 
                        ProxyCookieContainer.GetCookies(new Uri(ServerURL)))
                        if (ReturnCookie.Name.Equals(OldCookie.Name))
                            OldCookie.Value = ReturnCookie.Value;
                            CookieFound = true;
                    if (!CookieFound)

            Stream StreamResponse = ProxyResponse.GetResponseStream();
            int ResponseReadBufferSize = 256;
            byte[] ResponseReadBuffer = new byte[ResponseReadBufferSize];
            MemoryStream MemoryStreamResponse = new MemoryStream();

            int ResponseCount = StreamResponse.Read(ResponseReadBuffer, 0, 
            while ( ResponseCount > 0 )
                MemoryStreamResponse.Write(ResponseReadBuffer, 0, 
                ResponseCount = StreamResponse.Read(ResponseReadBuffer, 0, 

            byte[] ResponseData = MemoryStreamResponse.ToArray();
            string ResponseDataString = Encoding.ASCII.GetString(ResponseData);

            // While rendering HTML, parse and modify the URLs present
            if ( ProxyResponse.ContentType.StartsWith("text/html") )
                HTML.ParseHTML Parser = new HTML.ParseHTML();
                Parser.Source = ResponseDataString;                    
                while( !Parser.Eof() )
                    char ch = Parser.Parse();
                    if ( ch == 0 )
                        HTML.AttributeList Tag = Parser.GetTag();
                        if ( Tag["href"] != null )
                            if ( Tag["href"].Value.StartsWith(
                                @"/") )
                                WriteLog("URL " +  
                                    Tag["href"].Value + 
                                    " modified to " + URLPrefix + 
                                ResponseDataString = 
                                    "\"" + 
                                    Tag["href"].Value + 
                                    "\"", "\"" + 
                                    URLPrefix + Tag["href"].Value + 

                        if ( Tag["src"] != null )
                            if ( Tag["src"].Value.StartsWith(
                                @"/") )
                                WriteLog("URL " +  
                                    Tag["src"].Value + 
                                    " modified to " + 
                                    URLPrefix + Tag["src"].Value);
                                ResponseDataString = 
                                    "\"" + 
                                    Tag["src"].Value + 
                                    "\"", "\"" + 
                                    URLPrefix + Tag["src"].Value + 
                Context.Response.OutputStream.Write(ResponseData, 0, 

        catch ( Exception Ex )
            WriteLog("An error has occurred while requesting the URL 
                " + ServerURL + "(" + 
                Context.Request.Url.ToString() + ")\n" + 

    // Write debug log message
    private void WriteLog(string Message)
        FileStream FS = new FileStream(ConfigurationManager.AppSettings[
            "Log"], FileMode.Append, FileAccess.Write);
        string DateTimeString = DateTime.Now.ToString();
        Message = "[" + DateTimeString + "] " + Message + 
        byte[] FileBuffer = Encoding.ASCII.GetBytes(Message);
        FS.Write(FileBuffer, 0, (int)FileBuffer.Length);
        FS.Flush(); FS.Close();

Sample web.config Configuration File

   <add verb="*" path="*.sync" type="TryHTTPHandler.SyncHandler, 
       TryHTTPHandler" />
  <customErrors mode="Off" />
   <add key="UpchainProxy" value="true"/>
   <add key="Proxy" value="proxy1:80"/>
   <add key="Log" value="D:\\HTTPHandlerLog.rtf"/>

Reverse Proxy Server Setup

In order to setup the Reverse Proxy Server in IIS, the following steps need to be performed.

  1. Compile the project to get .NET assemblies and create a web.config configuration file.
  2. Create a virtual directory in IIS, say "Handler" and copy the .NET assemblies into the "bin" folder of the virtual directory.
  3. Also copy the web.config configuration file to the virtual directory.
  4. Right-click the virtual directory just created and go to Properties>Directory>Configuration>Mappings>Add
  5. Specify the new application extension that will be handled by the Reverse Proxy Server, say ".sync" in the "Extension" field.
  6. In the "Add/Edit Applications Mapping" dialog box, browse and specify aspnet_isapi.dll in the "Executable" field. (For example: c:\windows\\framework\v2.0.50727\aspnet_isapi.dll)
  7. Set the "Verbs" to "All Verbs".
  8. Ensure that "Verify that files exist" is unchecked.
  9. Click "OK" until you close the "Properties" dialog box.
  10. Navigate to the reverse proxy URL in IE. (For example: http://localhost/handler/stg2web.sync)
  11. The filename with ".sync" extension will be taken as the back-end server name.

If you navigate to say, http://localhost/handler/stg2web.sync/tso5/logon.cfm, you will get the response from the back-end server, http://stg2web/tso5/logon.cfm


Please note that these proxy features HTTP specifications and DO NOT support HTTPS. The following features are supported.

  3. HTTP Cookies
  4. URL Rewriting/Remapping
  5. Debug Logging


April 18, 2007 - Baseline (Version 1.0)


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


About the Author

Paramesh Gunasekaran
Technical Lead HCL Technologies
India India
Paramesh Gunasekaran is currently working as a Software Engineer in HCL Technologies, India. He obtained his Bachelor's degree in Information Technology from Anna University, India. His research areas include Computational Biology, Artificial Neural Networks and Network Engineering. He has also received international acclaim for authoring industry papers in these areas. He is a Microsoft Certified Professional in ASP.NET/C# and has also been working in .NET technologies for more than 8 years.


You may also be interested in...

Comments and Discussions

QuestionIssues with the sub directory folder access in website Pin
Member 812823420-Sep-11 9:29
memberMember 812823420-Sep-11 9:29 
QuestionNothing after ".sync/" works Pin
London Bentley7-Sep-11 10:24
memberLondon Bentley7-Sep-11 10:24 
I have this code configured and its working as is, if I hit my proxied server's root:

BUT, if I attempt to get a page beyond that, it doesnt work

For that I would get a 404. Again I dont have these specific urls, I'm just using your samples. For the page I'm testing, I proxy back the root of my website just perfectly, and its correctly updating links within the html to prepend the proxy server url. But if I attempt to get to anything beyond .sync it throws a 404. Is there something in my application config that needs to be updated? Its as if its not using the handler on anything but that root url
GeneralQueries : Reverse Proxy in C# .NET 2.0 Pin
lihkink12-Oct-10 1:48
memberlihkink12-Oct-10 1:48 
GeneralRe: Queries : Reverse Proxy in C# .NET 2.0 Pin
Paramesh Gunasekaran29-Nov-10 6:39
memberParamesh Gunasekaran29-Nov-10 6:39 
GeneralMy vote of 1 Pin
Syed Javed26-Aug-10 0:38
memberSyed Javed26-Aug-10 0:38 
GeneralRe: My vote of 1 Pin
Bill Seddon12-Nov-11 1:44
memberBill Seddon12-Nov-11 1:44 
QuestionHow to bypass the processrequest? Pin
vitiris4-Jan-10 18:10
membervitiris4-Jan-10 18:10 
GeneralOpen Source Reverse Proxy Pin
Paramesh Gunasekaran9-Dec-08 3:02
memberParamesh Gunasekaran9-Dec-08 3:02 
Generalproblem with appSettings Pin
Prateek Bahl14-Sep-08 15:01
memberPrateek Bahl14-Sep-08 15:01 
QuestionRegarding Host Header Pin
pmselvan_20005-Jul-08 8:27
memberpmselvan_20005-Jul-08 8:27 
GeneralContent Type Pin
tauchert22-May-08 3:18
membertauchert22-May-08 3:18 
QuestionAjax support Pin
easyal13-Mar-08 5:46
membereasyal13-Mar-08 5:46 
Questioncan you develope it if get paid? Pin
nolovelust20-Oct-07 9:50
membernolovelust20-Oct-07 9:50 
GeneralStrange results with Pin
neil young13-Oct-07 12:42
memberneil young13-Oct-07 12:42 
GeneralThe proxy name could not be resolved: 'proxy1' Pin
matchupsports26-Jun-07 9:37
membermatchupsports26-Jun-07 9:37 
GeneralRe: The proxy name could not be resolved: 'proxy1' Pin
Gunasekaran Paramesh26-Jun-07 12:33
memberGunasekaran Paramesh26-Jun-07 12:33 
GeneralRe: The proxy name could not be resolved: 'proxy1' Pin
matchupsports26-Jun-07 13:22
membermatchupsports26-Jun-07 13:22 
GeneralRe: The proxy name could not be resolved: 'proxy1' Pin
Gunasekaran Paramesh13-Jul-07 5:36
memberGunasekaran Paramesh13-Jul-07 5:36 
QuestionWhy IRequireSessionState? Pin
Holger Hansen21-Jun-07 23:40
memberHolger Hansen21-Jun-07 23:40 
AnswerRe: Why IRequireSessionState? Pin
Gunasekaran Paramesh13-Jul-07 5:38
memberGunasekaran Paramesh13-Jul-07 5:38 
QuestionOT, where did you take the images? Pin
Simone Busoli25-Apr-07 1:45
memberSimone Busoli25-Apr-07 1:45 
AnswerRe: OT, where did you take the images? Pin
Gunasekaran Paramesh29-May-07 0:02
memberGunasekaran Paramesh29-May-07 0:02 
QuestionHow to use it Pin
Khaled Al-Noami23-Apr-07 19:29
memberKhaled Al-Noami23-Apr-07 19:29 
AnswerRe: How to use it Pin
Gunasekaran Paramesh23-Apr-07 23:04
memberGunasekaran Paramesh23-Apr-07 23:04 
Generalwill it handle https Pin
DaveAnand23-Apr-07 15:35
memberDaveAnand23-Apr-07 15:35 
GeneralRe: will it handle https Pin
SeanKinsey23-Apr-07 21:18
memberSeanKinsey23-Apr-07 21:18 
GeneralRe: will it handle https Pin
Gunasekaran Paramesh23-Apr-07 23:01
memberGunasekaran Paramesh23-Apr-07 23:01 
GeneralRe: will it handle https Pin
tripletdad9931-Oct-07 5:44
membertripletdad9931-Oct-07 5:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171020.1 | Last Updated 20 Apr 2007
Article Copyright 2007 by Paramesh Gunasekaran
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid