OdeToCode IC Logo

Building A Simple File Server With OWIN and Katana

Monday, February 10, 2014

I have a scenario where I want to serve up HTML, JavaScript, and CSS files over HTTP from a .NET desktop application. This is the type of scenario Katana makes easy. Here is an example using a console application.

First, use NuGet to install a couple packages into the project.

install-package Microsoft.Owin.StaticFiles
install-package Microsoft.Owin.SelfHost

The source for the entire application is 17 lines of code, including using statements.

using System;
using Microsoft.Owin.Hosting;
using Owin;

namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            var url = "http://localhost:8080";
            WebApp.Start(url, builder => builder.UseFileServer(enableDirectoryBrowsing:true));            
            Console.WriteLine("Listening at " + url);
            Console.ReadLine();
        }
    }
}

The FileServer middleware will serve files from the same directory as the executable.

Static Files With OWIN and Katana

If you don’t want to use the default location, you can provide your own IFileSystem and serve files from anywhere. Katana currently provides two implementations of IFileSystem – one to serve embedded resources and one to serve files from the physical file system. You can construct a PhysicalFileSystem for an arbitrary location on the hard drive.

static void Main(string[] args)
{
    var url = "http://localhost:8080";
    var root = args.Length > 0 ? args[0] : ".";
    var fileSystem = new PhysicalFileSystem(root);

    var options = new FileServerOptions
    {
        EnableDirectoryBrowsing = true, 
        FileSystem = fileSystem                             
    };

    WebApp.Start(url, builder => builder.UseFileServer(options));            
    Console.WriteLine("Listening at " + url);
    Console.ReadLine();
}

The FileServer middleware is actually a composite wrapper around three other pieces of middleware – DefaultFiles (to select a default.html file, if present, when a request arrives for a directory), DirectoryBrowser (to list the contents of a directory if no default file is found), and StaticFile (to reply with the contents of a file in the file system). All three pieces of middleware are configurable through the UseFileServer extension method.

For example, the static file middleware will only serve files with a known content type. Although the list of known content types is extensive, you might need to serve files with uncommon extensions, in which case you can plug a custom  IContentTypeProvider into the static files middleware.

public class CustomContentTypeProvider : FileExtensionContentTypeProvider
{
    public CustomContentTypeProvider()
    {
        Mappings.Add(".nupkg", "application/zip");
    }
}

Now the final program looks like the following.

static void Main(string[] args)
{
    var url = "http://localhost:8080";
    var root = args.Length > 0 ? args[0] : ".";
    var fileSystem = new PhysicalFileSystem(root);
    var options = new FileServerOptions();
    
    options.EnableDirectoryBrowsing = true;
    options.FileSystem = fileSystem;         
    options.StaticFileOptions.ContentTypeProvider = new CustomContentTypeProvider();

    WebApp.Start(url, builder => builder.UseFileServer(options));            
    Console.WriteLine("Listening at " + url);
    Console.ReadLine();
}