Creating a web server in C#

This basically replicates the “Simple C# Web Server” that is done over at “David’s” Blog:

https://codehosting.net/blog/BlogEngine/post/Simple-C-Web-Server

I use pretty much the same code – I have given the code the once-over using Re-Sharper. Other than that, the only real difference is that this post actually tells you how to get started and how to demonstrate the thing – useful info for complete newbies, I think.

In Visual Studio create a new Console Application:

webserver1

In Program.cs we update the code to include the WebServer class which initializes the HttpListener prefixes – these represent the collection of prefix(s) used to store Uniform Resource Identifier (URI) values for the HttpListener object.

The WebServer class also implements methods to run and stop the web service.

The main program thread creates an instance of the web server, and runs it as a background thread, and which is stopped whenever the user presses any key. The thread runs the while loop to continuously listen for http requests. Once it ‘hears’ the http request the responder method returns the html string it created, this is converted into bytes and then used to create the http response in the form of a stream object:

var rstr = _responderMethod(ctx.Request);
var buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);

Full code listing of Program.cs as follows:

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading;

namespace WebServer
{
   public class WebServer
   {
      private readonly HttpListener _listener = new HttpListener();
      private readonly Func<HttpListenerRequest, string> _responderMethod;

      public WebServer(IReadOnlyCollection<string> prefixes, Func<HttpListenerRequest, string> method)
      {
         if (!HttpListener.IsSupported)
         {
            throw new NotSupportedException("Needs Windows XP SP2, Server 2003 or later.");
         }
            
         // URI prefixes are required eg: "http://localhost:8080/test/"
         if (prefixes == null || prefixes.Count == 0)
         {
            throw new ArgumentException("URI prefixes are required");
         }
        
         if (method == null)
         {
            throw new ArgumentException("responder method required");
         }

         foreach (var s in prefixes)
         {
            _listener.Prefixes.Add(s);
         }

         _responderMethod = method;
         _listener.Start();
      }

      public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
         : this(prefixes, method)
      {
      }

      public void Run()
      {
         ThreadPool.QueueUserWorkItem(o =>
         {
            Console.WriteLine("Webserver running...");
            try
            {
               while (_listener.IsListening)
               {
                  ThreadPool.QueueUserWorkItem(c =>
                  {
                     var ctx = c as HttpListenerContext;
                     try
                     {
                        if (ctx == null)
                        {
                           return;
                        }
                           
                        var rstr = _responderMethod(ctx.Request);
                        var buf = Encoding.UTF8.GetBytes(rstr);
                        ctx.Response.ContentLength64 = buf.Length;
                        ctx.Response.OutputStream.Write(buf, 0, buf.Length);
                     }
                     catch
                     {
                        // ignored
                     }
                     finally
                     {
                        // always close the stream
                        if (ctx != null)
                        {
                           ctx.Response.OutputStream.Close();
                        }
                     }
                  }, _listener.GetContext());
               }
            }
            catch (Exception ex)
            {
               // ignored
            }
         });
      }

      public void Stop()
      {
         _listener.Stop();
         _listener.Close();
      }
   }

   internal class Program
   {
      public static string SendResponse(HttpListenerRequest request)
      {
         return string.Format("<HTML><BODY>My web page.<br>{0}</BODY></HTML>", DateTime.Now);
      }

      private static void Main(string[] args)
      {
         var ws = new WebServer(SendResponse, "http://localhost:8080/test/");
         ws.Run();
         Console.WriteLine("A simple webserver. Press a key to quit.");
         Console.ReadKey();
         ws.Stop();
      }
   }
}

Before running the server I open up a web browser (Chrome in this case), and enter the example URI prefix we use in this program ie http://localhost:8080/test/.

As you can see the site cannot be reached as the server has not been started yet.

webserver2

I then start running the web server console application:

webserver3

The web browser content is updated with the newly created response stream as shown:

webserver4

Latest Comments

  1. John McCourt 17 September 2018
  • nalor 13 October 2018
  • Gijs van der Meijde 29 November 2018
    • Andy 29 November 2018
  • Sandy 18 December 2018
  • Ali 25 January 2019
    • Andy 25 January 2019
    • Gonza 12 August 2019
  • acki4711 20 August 2019
    • acki4711 21 August 2019
  • acki4711 22 August 2019
  • roy 28 September 2019
    • Andy 28 September 2019
  • Fabian 7 January 2020
  • Genzi 2 July 2020
    • Andy 3 July 2020
    • Vincie 14 February 2021
      • Andy 14 February 2021
  • Genzi 2 July 2020
  • jos 16 July 2021
  • Leave a Reply