Creating a HTTP Server in C♯

(Image from here.)
I discovered the HttpListener class in .NET the other day, and decided to take a look. It turns out that it's way easier to use than doing it all by hand as I had to do in my 08241 Networking module a few months ago. I thought I'd write a post about it so that you can see how easy it is and use the same technique yourself. You might want to add a HTTP status reporting system to your program, or use it to serve a front-end GUI. You could even build a real-time app with WebSockets.
As with all my tutorials - this post is a starting point, not an ending point. Refactor it to your heart's content!
To start off, let's create a new C♯ console project and create an instance of it:
using System;
using System.Net;
class MainClass
{
public static void Main(string[] args)
{
HttpListener listener = new HttpListener();
}
}
This should look pretty familiar to you. If not, then I can recommend the C♯ yellow book by Rob Miles. This is all rather boring so far, so let's move on quickly.
listener.Prefixes.Add("http://*:3333/");
listener.Start();
C♯'s HttpListener works on prefixes. It parses the prefix to work out what it should listen on and for what. The above listens for HTTP requests from anyone on port 3333. Apparently you can listen for HTTPS requests using this class too, but I'd recommend putting it behind some kind of proxy like NginX instead and let that handle the TLS certificates instead.
We also start the listener listening for requests too, because it doesn't listen for requests by default.
while(true)
{
HttpListenerContext cycle = listener.GetContext();
Console.WriteLine("Got request for {0} from {1}.", cycle.Request.RawUrl, cycle.Request.RemoteEndPoint);
StreamWriter outgoing = new StreamWriter(cycle.Response.OutputStream);
}
This next part is the beginning of the main request / response loop. The highlighted line is the important one - it retrieves the next pending request, waiting for it if necessary. The following lines log to the console about the latest request, and set up a StreamWriter to make it easier to send the response to the requester.
The final piece of the puzzle actually sending the request and moving onto the next one.
outgoing.WriteLine("It works!");
outgoing.Close();
cycle.Response.Close();
Actually writing the response is easy - all you have to do is write it to the StreamWriter. Then all you have to do is call Close() on the stream writer and the Response object, and you're done! Here's the whole thing:
using System;
using System.Net;
using System.IO;
namespace HttpServerTest
{
class MainClass
{
public static void Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://*:3333/");
listener.Start();
while(true)
{
HttpListenerContext cycle = listener.GetContext();
Console.WriteLine("Got request for {0} from {1}.", cycle.Request.RawUrl, cycle.Request.RemoteEndPoint);
StreamWriter outgoing = new StreamWriter(cycle.Response.OutputStream);
cycle.Response.ContentType = "text/plain";
outgoing.WriteLine("It works!");
outgoing.Close();
cycle.Response.Close();
}
}
}
}
That's all you really need to create a simple HTTP server in C♯. You should extend this by putting everything that could go wrong in a try..catch statement to prevent the server from crashing. You could also write a simple find / replace templating system to make it easier to serve files from your new HTTP server. Refactoring the above to make it asynchronous wouldn't be a bad idea either.
Have you been building anything interesting recently? Post about in the comments below!
Reddit




(Header image from
(Image from 
