totem totem - 1 month ago 15
C# Question

How to serve relative files from HttpListener

I am learning the

HttpListener
. I am creating a small app that is a webserver by using the
HttpListener
(following
http://msdn.microsoft.com/en-us/library/system.net.httplistener%28v=vs.110%29.aspx and https://www.codehosting.net/blog/BlogEngine/post/Simple-C-Web-Server.aspx). Note, no ASP.NET stuff.

In my function that is called from
_responderMethod
, I basically return HTML (that is read from a physical file on disk) which contains something like:

...
<link href="css/ui-lightness/jquery-ui-1.10.4.custom.css" rel="stylesheet">
<script src="js/jquery-1.10.2.js"></script>
<script src="js/jquery-ui-1.10.4.custom.js"></script>
...


However, as to be expected, the
.css
and
.js
files don't seem to be served (I can tell because there's no styles or behaviors as expected on the client after the html has been served).

How do I go about serving this files, do I need to do something with
HttpServerUtility.MapPath
? if so, could you point me to some examples on that?

Or do I need to scan the HTML I am about to serve and open those files up (recursively) read and return those? I hope not.

BTW, the C# code that serves this is as follows, where my
_responderMethod
just returns the string of the HTML file as it is stated above:

I initialize and start the server as follows:

WebServer ws = new WebServer(program.SendResponse, "http://<myip>:8080/");
ws.Run();


the class constructor is pretty much:

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

public WebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
// A responder method is required
if (method == null)
throw new ArgumentException("method");

foreach (string s in prefixes)
_listener.Prefixes.Add(s);

_responderMethod = method;
_listener.Start();
}
public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method) { }


the
.Run()
is:

public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch { } // suppress any exceptions
});
}


My
SendResponse()
:

public string SendResponse(HttpListenerRequest request)
{
return File.ReadAllText(@"static\index.html");
}

Answer

If your HTML specifies script or CSS files that are on your site, the client browser is going to request them. Your server has to serve up those files, too. Scripts and CSS files are text files that you serve in much the same way that you serve HTML files, although you'll want to be sure to change the content type header accordingly. You serve binary files (images, etc.) in binary format. Again, you'll want to be sure to set the content type to indicate that it's an image.