I wanted to set up a simple interface to serve information online without having to install a bunch of stuff and read through a bunch of documentation about configuration. I came up with a class and an interface in c# that should simplify/standardize some of my other projects.
The handler interface provides access to the request and response streams for each request
interface IRequestHandler { //same idea as a java servlet void handle(HttpListenerContext context); }
Here is a simple single threaded server; requests block while processing. There are performance issues here if you intend to have your request handler doing any heavy lifting, but for doing something like processing a get request and sending/receiving some stuff on a serial port it gets the job done. This implementation can always be swapped out, what matters is giving my IRequestHandlers something to run from.
class Server { protected HttpListener httpListener; protected IRequestHandler requestHandler; //path is something like http://localhost:8000/ public Server(string path, IRequestHandler requestHandler) { this.requestHandler = requestHandler; httpListener = new HttpListener(); httpListener.Prefixes.Add(path); } public void begin() { //does not return until server dies httpListener.Start(); while (true) { HttpListenerContext context = httpListener.GetContext(); requestHandler.handle(context); } } }
To get an idea how to put the IRequestHandler to use I wrote a (hopefully) self-explanatory example. I havn't used this in any long running programs, so hopefully calling OutputStream.close() is all I have to do to properly kill the HttpListenerContext.
class SimpleHandler { public void handle(HttpListenerContext context) { byte[] bytes = Encoding.ASCII.GetBytes("hello world"); context.Response.OutputStream.Write(bytes, 0, bytes.Length); context.Response.OutputStream.Close(); } }
This is a little more useful for serving up static content.
class StaticDataHandler : ServerFramework.IRequestHandler { private byte[] data; public StaticDataHandler(string dataString) { data = Encoding.ASCII.GetBytes(dataString); } public StaticDataHandler(byte[] dataBytes) { data = dataBytes; } public void handle(HttpListenerContext context) { context.Response.OutputStream.Write(data, 0, data.Length); context.Response.OutputStream.Close(); } }
And here is how you would serve a couple static pages, the idea is to run one server per page.
class MyProgram { static void Main(string[] args) { //make the handler objects IRequestHandler pageHandler0 = new StaticDataHandler("this is page 1"); IRequestHandler pageHandler1 = new StaticDataHandler("this is page 2"); //make the server objects ServerFramework.Server server0 = new ServerFramework.Server("http://localhost:8000/foo/", pageHandler0); ServerFramework.Server server1 = new ServerFramework.Server("http://localhost:8000/bar/", pageHandler1); //start the servers in threads; Server.begin blocks forever Thread threadedserver0 = new Thread(server0.begin); Thread threadedserver1 = new Thread(server1.begin); threadedserver0.Start(); threadedserver1.Start(); threadedserver0.Join(); threadedserver1.Join(); } }