Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

An HttpListener Server for Handling AJAX POST Requests

4.83/5 (13 votes)
30 May 2013CC (ASA 3U)4 min read 127.1K   8.2K  
A very simple HttpListener server which implements handling AJAX requests. Made to present a web service endpoint in your Windows Forms application.

Program Screen

Introduction

HttpListenerServer is a multithreaded simple webserver written in C#, made in Visual Studio 2012. This project uses the HttpListener class (System.Net) to create a simple webserver. This class provides a simple HTTP protocol listener. The webserver is capable of listening to multiple calls through multiple domains. The request data (JSON/Text) is also handled in the web server callback. This webserver listens for requests on port 8000 on the localhost.

The code also includes commented code for response and for sending and receiving custom headers in the request.

Background

Web servers and web services are generally hosted on IIS, Apache, or Tomcat. These often require complex installations and configuration. You can host your ASP.NET web applications or PHP web sites.

An ASMX webservice can easily be created with an ASP.NET web application. You can also create a webservice endpoint using [WebMethod] before your method declaration. This method should be a static method in the code behind file of the web page.

This application is a part of another application which required a simple stand alone http web service listener. A simple web service was required in a Windows Forms application and HttpListener class met my requirements.

Using the Code

The project is a simple Windows Forms application with target .NET Framework 4.0.

Now, let's get started with how the code works and how you can use it in your .NET C# application.

First of all, define these variables in your class:

C#
static HttpListener listener;
private Thread listenThread1;

The Form load event method is as follows:

C#
private void Form1_Load(object sender, EventArgs e)
{
    listener = new HttpListener();
    listener.Prefixes.Add("http://localhost:8000/");
    listener.Prefixes.Add("http://127.0.0.1:8000/");
    listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;

    listener.Start();
    this.listenThread1 = new Thread(new ParameterizedThreadStart(startlistener));
    listenThread1.Start();
}

Instantiate the HttpListener and add the prefixes on which the program should listen. If the request has the URI that matches this URI prefix, then the program will handle that request.

C#
listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8000/");
listener.Prefixes.Add("http://127.0.0.1:8000/");

More on URI Prefixes (From MSDN)

A URI prefix string is composed of a scheme (http or https), a host, an optional port, and an optional path. An example of a complete prefix string is "http://www.contoso.com:8080/customerData/". Prefixes must end in a forward slash ("/"). The HttpListener object with the prefix that most closely matches a requested URI responds to the request. Multiple HttpListener objects cannot add the same prefix; a Win32Exception exception is thrown if an HttpListener adds a prefix that is already in use. When a port is specified, the host element can be replaced with "*" to indicate that the HttpListener accepts requests sent to the port if the requested URI does not match any other prefix. For example, to receive all requests sent to port 8080 when the requested URI is not handled by any HttpListener, the prefix is "http://*:8080/". Similarly, to specify that the HttpListener accepts all requests sent to a port, replace the host element with the "+" character, "https://+:8080". The "*" and "+" characters can be present in prefixes that include paths.

An HttpListener can require client authentication. The following line states that no authentication is required for the http request.

C#
listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;

The following code starts the listener to listen on the specified prefixes. A new thread is created and passed the method 'startlistener' which is a blocking method and can't be run on the UI thread. We can also pass any object to the method in the thread but it is not my requirement so I haven't passed anything to the thread Start() method.

C#
listener.Start();
this.listenThread1 = new Thread(new ParameterizedThreadStart(startlistener));
listenThread1.Start();

The thread is blocked until a client sends a request to the listener. The ListenerCalback function is called when a request is received and needs to be handled.

C#
private void startlistener(object s)
{
    while (true)
    {               
        ////blocks until a client has connected to the server
        ProcessRequest();
    }
}

private void ProcessRequest()
{
    var result = listener.BeginGetContext(ListenerCallback, listener);
    result.AsyncWaitHandle.WaitOne();
}

BeginGetContext begins asynchronously retrieving an incoming request. We use AsyncWaitHandle.WaitOne() to prevent this thread from terminating while the asynchronous operation completes.

Our code to the ListenerCallback is as follows:

C#
private void ListenerCallback(IAsyncResult result)
{
    var context = listener.EndGetContext(result);
    Thread.Sleep(1000);
    var data_text = new StreamReader(context.Request.InputStream, 
    context.Request.ContentEncoding).ReadToEnd();
    
    //functions used to decode json encoded data.
    //JavaScriptSerializer js = new JavaScriptSerializer();
    //var data1 = Uri.UnescapeDataString(data_text);
    //string da = Regex.Unescape(data_text);
    // var unserialized = js.Deserialize(data_text, typeof(String));
    
    var cleaned_data = System.Web.HttpUtility.UrlDecode(data_text);
    
    context.Response.StatusCode = 200;
    context.Response.StatusDescription = "OK";
    
    //use this line to get your custom header data in the request.
    //var headerText = context.Request.Headers["mycustomHeader"];
    
    //use this line to send your response in a custom header
    //context.Response.Headers["mycustomResponseHeader"] = "mycustomResponse";
    
    MessageBox.Show(cleaned_data);
    context.Response.Close();
}

The EndGetContext method completes an asynchronous operation to retrieve an incoming client request. The context contains the HttpListenerRequest object named Request and the HttpListenerResponse named Response depending on the GET/POST request.

The POST data is received via the InputStream. I am also specifying the encoding used to make things easier.

C#
var data_text = new StreamReader(context.Request.InputStream, 
context.Request.ContentEncoding).ReadToEnd();

The following functions can be used to clean/decode/unescape the data. I had to use the UrlDecode method to unescape the data. For that to work, you have to add a reference to the System.Web DLL in your application.

C#
//functions used to decode json encoded data.
//JavaScriptSerializer js = new JavaScriptSerializer();
//var data1 = Uri.UnescapeDataString(data_text);
//string da = Regex.Unescape(data_text);
// var unserialized = js.Deserialize(data_text, typeof(String));

var cleaned_data = System.Web.HttpUtility.UrlDecode(data_text);

We are sending a POST request and do not require a response, but you can use these lines to send the response in the header:

C#
//use this line to get your custom header data in the request.
//var headerText = context.Request.Headers["mycustomHeader"];

//use this line to send your response in a custom header
//context.Response.Headers["mycustomResponseHeader"] = "mycustomResponse";

You can also send the response via the context.Response.OutputStream and flush the data using:

C#
System.IO.Stream output = response.OutputStream;
output.Write(buffer,0,buffer.Length);

Where buffer is a byte array containing the response that you want to send.

Finally, we send an OK response via these lines of code:

C#
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";

You can call the listener.Stop() method in your application for the listener to stop listening on the specified port and prefixes. Keep in mind that only one listener can be listening to a port, otherwise you will get an exception.

Points of Interest

HttpListenerServer only implements a simple server for handling Ajax requests. You can also extend this code to send a web page as a response or host your own web pages.

Software Requirements

  • Visual Studio 2012 (can run on lower versions)
  • Administrator rights are required for HttpListener class (System.Net).

History

  • Initial release. v1.0.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-Share Alike 3.0 Unported License