Starbeamrainbowlabs

Stardust
Blog

Creating a HTTP Server in C♯

An image looks cool.

(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();
            }
        }
    }
}

(Hastebin, Raw)

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!

Tag Cloud

3d 3d printing account algorithms android announcement architecture archives arduino artificial intelligence artix assembly async audio automation backups bash batch blog bookmarklet booting bug hunting c sharp c++ challenge chrome os cluster code codepen coding conundrums coding conundrums evolved command line compilers compiling compression containerisation css dailyprogrammer data analysis debugging demystification distributed computing documentation downtime electronics email embedded systems encryption es6 features ethics event experiment external first impressions future game github github gist gitlab graphics hardware hardware meetup holiday holidays html html5 html5 canvas infrastructure interfaces internet interoperability io.js jabber jam javascript js bin labs learning library linux lora low level lua maintenance manjaro network networking nibriboard node.js operating systems own your code pepperminty wiki performance phd photos php pixelbot portable privacy problem solving programming problems projects prolog protocol protocols pseudo 3d python reddit redis reference releases rendering resource review rust searching secrets security series list server software sorting source code control statistics storage svg talks technical terminal textures thoughts three thing game three.js tool tutorial twitter ubuntu university update updates upgrade version control virtual reality virtualisation visual web website windows windows 10 xmpp xslt

Archive

Art by Mythdael