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:
static HttpListener listener;
private Thread listenThread1;
The Form load event method is as follows:
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.
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.
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.
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.
private void startlistener(object s)
{
while (true)
{
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:
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();
var cleaned_data = System.Web.HttpUtility.UrlDecode(data_text);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
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.
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.
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:
You can also send the response via the context.Response.OutputStream
and flush the data using:
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:
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