Click here to Skip to main content
13,633,447 members
Click here to Skip to main content
Add your own
alternative version


86 bookmarked
Posted 28 Nov 2008
Licenced CPOL

Simple Reverse Proxy in C# 2.0 (description and deployment)

, 28 Nov 2008
Rate this:
Please Sign up or sign in to vote.
This article describes how to develop a reverse proxy in C# using the IIS HTTPHandlers.

Structure of Reverse Proxy


This article describes how to develop a Reverse Proxy in C# using the IIS HTTPHandlers, not manipulating incoming HTTP requests, but only by transferring all requests to the internal server (Remote Server).


Wikipedia says, "A reverse proxy or surrogate is a proxy server that is installed within the neighborhood of one or more servers. Typically, reverse proxies are used in front of Web servers. All connections coming from the Internet addressed to one of the Web servers are routed through the proxy server, which may either deal with the request itself, or pass the request wholly or partially to the main web servers. A reverse proxy dispatches in-bound network traffic to a set of servers, presenting a single interface to the caller. (...)".

To write the code, I was inspired by articles of Vincent Brossier and Paramesh Gunasekaran here at CodeProject.

Using the Code

The code below is the core of the reverse proxy server.

The class ReverseProxy is the core of the application managing the communication between the navigator and the proxy server... points [1] and [4] on the above picture. The class RemoteServer manages communication between the proxy server (front-end to Internet) and the remote server (internal server)... points [2] and [3] on the above picture.

The class ReverseProxy:

  1. Creates a connection to the remote server to redirect all requests.
  2. Creates a request with the same data in the navigator request.
  3. Sends the request to the remote server and returns the response.
  4. Sends the response to the client (and handles cookies, if available).
  5. Closes streams
namespace ReverseProxy
    /// <summary>
    /// Handler all Client's requests and deliver the web site
    /// </summary>
    public class ReverseProxy : IHttpHandler, 
        /// <summary>
        /// Method calls when client request the server
        /// </summary>
        /// <param name="context">HTTP context for client</param>
        public void ProcessRequest(HttpContext context)
            // Create a connexion to the Remote Server to redirect all requests
            RemoteServer server = new RemoteServer(context);
            // Create a request with same data in navigator request
            HttpWebRequest request = server.GetRequest();

            // Send the request to the remote server and return the response
            HttpWebResponse response = server.GetResponse(request);
            byte[] responseData = server.GetResponseStreamBytes(response);

            // Send the response to client
            context.Response.ContentEncoding = Encoding.UTF8;
            context.Response.ContentType = response.ContentType;
            context.Response.OutputStream.Write(responseData, 0, 

            // Handle cookies to navigator
            // Close streams

        public bool IsReusable
            get { return true; }


The class RemoteServer contains many methods:

  • Constructor to initialize the communication with the remote server (defined by the URL).
  • GetRequest creates an HttpWebRequest object connected to the remote server and sends all "parameters" (arguments, POST data, cookies, ...).
  • GetResponse uses the previous object and gets the response from the remote server.
  • GetResponseStreamBytes converts the HttpWebResponse (returned by the previous method) to an array of bytes.
  • SetContextCookies sends cookies to the navigator context.
namespace ReverseProxy
    /// <summary>
    /// Manage communication between the proxy server and the remote server
    /// </summary>
    internal class RemoteServer
        string _remoteUrl;
        HttpContext _context;

        /// <summary>
        /// Initialize the communication with the Remote Server
        /// </summary>
        /// <param name="context">Context </param>
        public RemoteServer(HttpContext context)
            _context = context;

            // Convert the URL received from navigator to URL for server
            string serverUrl = ConfigurationSettings.AppSettings["RemoteWebSite"];
            _remoteUrl = context.Request.Url.AbsoluteUri.Replace("http://" + 
                         context.Request.Url.Host + 
                         context.Request.ApplicationPath, serverUrl);

        /// <summary>
        /// Return address to communicate to the remote server
        /// </summary>
        public string RemoteUrl
                return _remoteUrl;

        /// <summary>
        /// Create a request the remote server
        /// </summary>
        /// <returns>Request to send to the server </returns>
        public HttpWebRequest GetRequest()
            CookieContainer cookieContainer = new CookieContainer();

            // Create a request to the server
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);

            // Set some options
            request.Method = _context.Request.HttpMethod;
            request.UserAgent = _context.Request.UserAgent;
            request.KeepAlive = true;
            request.CookieContainer = cookieContainer;

            // Send Cookie extracted from the incoming request
            for (int i = 0; i < _context.Request.Cookies.Count; i++)
                HttpCookie navigatorCookie = _context.Request.Cookies[i];
                Cookie c = new Cookie(navigatorCookie.Name, navigatorCookie.Value);
                c.Domain = new Uri(_remoteUrl).Host;
                c.Expires = navigatorCookie.Expires;
                c.HttpOnly = navigatorCookie.HttpOnly;
                c.Path = navigatorCookie.Path;
                c.Secure = navigatorCookie.Secure;

            // For POST, write the post data extracted from the incoming request
            if (request.Method == "POST")
                Stream clientStream = _context.Request.InputStream;
                byte[] clientPostData = new byte[_context.Request.InputStream.Length];
                clientStream.Read(clientPostData, 0, 

                request.ContentType = _context.Request.ContentType;
                request.ContentLength = clientPostData.Length;
                Stream stream = request.GetRequestStream();
                stream.Write(clientPostData, 0, clientPostData.Length);

            return request;


        /// <summary>
        /// Send the request to the remote server and return the response
        /// </summary>
        /// <param name="request">Request to send to the server </param>
        /// <returns>Response received from the remote server
        ///           or null if page not found </returns>
        public HttpWebResponse GetResponse(HttpWebRequest request)
            HttpWebResponse response;

                response = (HttpWebResponse)request.GetResponse();
            catch (System.Net.WebException)
                // Send 404 to client 
                _context.Response.StatusCode = 404;
                _context.Response.StatusDescription = "Page Not Found";
                _context.Response.Write("Page not found");
                return null;

            return response;

        /// <summary>
        /// Return the response in bytes array format
        /// </summary>
        /// <param name="response">Response received
        ///             from the remote server </param>
        /// <returns>Response in bytes </returns>
        public byte[] GetResponseStreamBytes(HttpWebResponse response)
            int bufferSize = 256;
            byte[] buffer = new byte[bufferSize];
            Stream responseStream;
            MemoryStream memoryStream = new MemoryStream();
            int remoteResponseCount;
            byte[] responseData;

            responseStream = response.GetResponseStream();
            remoteResponseCount = responseStream.Read(buffer, 0, bufferSize);

            while (remoteResponseCount > 0)
                memoryStream.Write(buffer, 0, remoteResponseCount);
                remoteResponseCount = responseStream.Read(buffer, 0, bufferSize);

            responseData = memoryStream.ToArray();



            return responseData;

        /// <summary>
        /// Set cookies received from remote server to response of navigator
        /// </summary>
        /// <param name="response">Response received
        ///                 from the remote server</param>
        public void SetContextCookies(HttpWebResponse response)

            foreach (Cookie receivedCookie in response.Cookies)
                HttpCookie c = new HttpCookie(receivedCookie.Name, 
                c.Domain = _context.Request.Url.Host;
                c.Expires = receivedCookie.Expires;
                c.HttpOnly = receivedCookie.HttpOnly;
                c.Path = receivedCookie.Path;
                c.Secure = receivedCookie.Secure;

Sample "Web.Config" File

The config file sets where all the requests received by the reverse proxy server will be sent (for example: on port 81).

    <add key="RemoteWebSite" value="" />
      <add verb="*" path="*" 

          type="ReverseProxy.ReverseProxy, ReverseProxy"/>


In order to setup the reverse proxy server in IIS, the following steps need to be performed:

  1. Compile the project to get the .NET assemblies, and create a web.config configuration file.
  2. Create a new virtual directory (or a new website) in IIS, and copy the .NET assemblies into the "bin" folder, and the web.config to the root folder.
  3. Right-click the virtual directory just created, and go to "Properties / Home Directory / Configuration > Mappings" (see picture below), and add "wildcard application maps" to "aspnet_isapi.dll" (uncheck Verify that file exists).
  4. Click "OK" until you close the "Properties" dialog box.
  5. Set the correct IP of the remote server in web.config.

IIS Configuration

Points of Interest

This article explains how HTTPHandler works and how to capture the flow received by the web server IIS and transfer it (unchanged) to another server.


  • November 21, 2008 - 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

Denis Voituron
Team Leader Trasys
Belgium Belgium
I am a trained civil engineer in computer science. After a few years as project manager of multimedia applications, I set up my IT company for almost 10 years. We created a CMS, software and websites for companies and public administrations. We received the award for “best company” for this job.

So, I obtained skills in several areas, and expertise in architecture, development and methodologies (MSF, Oracle, SQL Server, .NET).

I also have several years of experience in training for architecture and design software, database administration and network architecture of Windows.

You may also be interested in...


Comments and Discussions

QuestionReverse Proxy without IIS using c# Pin
Ameer Hamza20-Feb-16 5:49
memberAmeer Hamza20-Feb-16 5:49 
QuestionNice work, but how do you handle 304 code? Pin
Hardy Wang5-Dec-12 14:56
memberHardy Wang5-Dec-12 14:56 
QuestionHow is this working? Pin
Tech12329-Nov-12 10:53
memberTech12329-Nov-12 10:53 
QuestionError could not load type 'ReverseProxy,.ReverseProxy' from assembly Pin
RussellJacobs12-Apr-12 4:48
memberRussellJacobs12-Apr-12 4:48 
AnswerRe: Error could not load type 'ReverseProxy,.ReverseProxy' from assembly Pin
Gio Bejarasco8-Jun-12 9:01
memberGio Bejarasco8-Jun-12 9:01 
QuestionIssues with the url Pin
Maggi121-Sep-11 5:02
memberMaggi121-Sep-11 5:02 
AnswerRe: Issues with the url Pin
Tech12329-Nov-12 10:51
memberTech12329-Nov-12 10:51 
GeneralMy vote of 5 Pin
Member 35036912-Aug-10 8:16
memberMember 35036912-Aug-10 8:16 
GeneralAdd/Edit this code to make error messages much more descriptive Pin
twebb721-Jul-09 18:42
membertwebb721-Jul-09 18:42 
GeneralRe: Add/Edit this code to make error messages much more descriptive Pin
Andreag711-Jun-11 1:19
memberAndreag711-Jun-11 1:19 
QuestionDifferent port Pin
DeanBlans26-May-09 9:35
memberDeanBlans26-May-09 9:35 
AnswerRe: Different port Pin
Denis Voituron26-May-09 10:18
memberDenis Voituron26-May-09 10:18 
GeneralRe: Different port [modified] Pin
DeanBlans26-May-09 22:39
memberDeanBlans26-May-09 22:39 
Generalhttps Pin
toronja7230-Apr-09 2:18
membertoronja7230-Apr-09 2:18 
GeneralRe: https Pin
Denis Voituron30-Apr-09 9:35
memberDenis Voituron30-Apr-09 9:35 
QuestionWorks with aspx, asmx -- but not gif, jpg, css, etc... [modified] Pin
twebb723-Feb-09 9:42
membertwebb723-Feb-09 9:42 
QuestionRe: Works with aspx, asmx -- but not gif, jpg, css, etc... Pin
Denis Voituron3-Feb-09 10:13
memberDenis Voituron3-Feb-09 10:13 
QuestionRe: Works with aspx, asmx -- but not gif, jpg, css, etc... [modified] Pin
twebb723-Feb-09 15:16
membertwebb723-Feb-09 15:16 
AnswerRe: Works with aspx, asmx -- but not gif, jpg, css, etc... Pin
twebb723-Feb-09 15:54
membertwebb723-Feb-09 15:54 
GeneralRe: Works with aspx, asmx -- but not gif, jpg, css, etc... Pin
Gio Bejarasco7-Jun-12 20:12
memberGio Bejarasco7-Jun-12 20:12 
GeneralRe: Works with aspx, asmx -- but not gif, jpg, css, etc... Pin
Gio Bejarasco8-Jun-12 11:45
memberGio Bejarasco8-Jun-12 11:45 
AnswerRe: Works with aspx, asmx -- but not gif, jpg, css, etc... [modified] Pin
Tech12329-Nov-12 10:51
memberTech12329-Nov-12 10:51 
General404 Pin
Moshe Katz8-Jan-09 13:52
memberMoshe Katz8-Jan-09 13:52 
GeneralRe: 404 Pin
twebb721-Jul-09 18:44
membertwebb721-Jul-09 18:44 
GeneralDeployment on Win Server 2003 and IIS 6 Pin
Rombolt15-Dec-08 9:53
memberRombolt15-Dec-08 9:53 

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 | Cookies | Terms of Use | Mobile
Web03-2016 | 2.8.180712.1 | Last Updated 28 Nov 2008
Article Copyright 2008 by Denis Voituron
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid