Many of us take for granted the existence of ASP.NET Core to access HTTP in the .NET world. It’s the foundation for most web implementations in the .NET space and provides functionality for all the programming paradigms in the ASP.NET ecosystem.

So it was genuinely surprising when I found a new HTTP server implementation on NuGet. Not only new but also very well thought out and accessible to many folks.

In this post, we’ll look at Sisk, and HTTP server implementation designed to be 100% open-source, multi-platform, and written in C#.

What is Sisk?

Sisk is an HTTP Server implementation separate from ASP.NET Core. That means there is no high-level overlap between this library and that of the ASP.NET Core ecosystem. Sisk’s HTTP Server implementation provides functionality such as routing, request handling, middleware, logging, web sockets, server-sent events, and more. Again, all independent of what you’re used to with Razor Pages, ASP.NET Core MVC, or Minimal APIs. The documentation site claims to be “code-pattern-agnostic, “ meaning you can code however you want. An HTTP server is helpful in many scenarios, but why would you want a different HTTP server implementation outside of ASP.NET Core?

Why does Sisk exist?

The documentation site does a great job explaining what Sisk is, but why does it exist? From a consumer’s perspective, there are several reasons to want a separate HTTP server from what ships with ASP.NET Core.

This HTTP server implementation provides a much more straightforward programming model than the one provided by ASP.NET Core. It’s focused on providing HTTP functionality. That’s it. There’s no UI framework, so you must provide one yourself. The features of ASP.NET Core can quickly become a burden in some scenarios.

Running a simple HTTP server can be helpful in local scenarios where UI talks to a local backend. A local host can serve application functionality while multiple UI instances and widgets interact with the server process. Sisk also has the advantage of providing multiple listening ports and making adding additional ones more straightforward.

HTTP servers are typically essential to distributed architectures, where services need a communication protocol to interoperate. HTTP is commonly used as a transport because it is flexible and battle-hardened. Containerizing processes with exposed simple HTTP servers can reduce the size of images and ultimately improve deployment throughput. Given Sisk has Native AOT support, I bet you can get some efficient images.

Finally, writing an HTTP server is a fun and cool thing. While familiar, the programming model for Sisk is different enough to be a friendly programming alternative to ASP.NET Core.

Your First Sisk HTTP Server App

To start with Sisk, you’ll need to create a .NET console application first. Once you’ve created the console application, you’ll want to install the following NuGet package.

dotnet add package Sisk.HttpServer

Now, let’s write a two-endpoint HTTP server application.

using Sisk.Core.Http;  
using static Sisk.Core.Routing.RouteMethod;  
  
var http = HttpServer.Emit(  
    insecureHttpPort: 5000, host: out _, configuration: out _,  
    router: out var router  
);  
  
router.SetRoute(Get, "/", _ => new(200) {  
    Content = new StringContent("Hello, World")  
});  
  
router.SetRoute(Get, "/hi/<name>", req =>  
{  
    var name = req.Query["name"];  
    return new(200) {  
        Content = new HtmlContent($"<h1>Hello, {name}</h1>")  
    };
});  
  
http.Start();  
Console.WriteLine($"HTTP Server is listening on {http.ListeningPrefixes[0]}");  
Console.ReadKey();

Running our application, we see that both endpoints are now accessible in our browser. You’ll also note that our /hi/<name> path uses a route value. We can access the entire request through the HttpRequest instance, which Sisk passes to our action.

Sisk also has a way to define endpoints in different locations. Let’s add a new widgets endpoint. First, let’s create a Widgets class to hold our endpoint.

using Sisk.Core.Http;  
using Sisk.Core.Routing;  
using static Sisk.Core.Routing.RouteMethod;  
  
public class Widgets  
{  
    [Route(Get, "/widgets")]  
    static HttpResponse Index(HttpRequest request)  
    {        
	    HttpResponse res = new() {  
            Content = new StringContent("Index")  
        };        return res;  
    }
}

Note that all endpoints must be static implementations. Sisk will fail to turn your methods into delegates otherwise.

Next, let’s add our new endpoint to our previous example.

using Sisk.Core.Http;  
using static Sisk.Core.Routing.RouteMethod;  
  
var http = HttpServer.Emit(  
    insecureHttpPort: 5000, host: out _, configuration: out _,  
    router: out var router  
);  
  
router.SetRoute(Get, "/", _ => new(200) {  
    Content = new StringContent("Hello, World")  
});  
  
router.SetRoute(Get, "/hi/<name>", req =>  
{  
    var name = req.Query["name"];  
    return new(200) {  
        Content = new HtmlContent($"<h1>Hello, {name}</h1>")  
    };
});

// register the Widgets endpoint from our class
router.SetObject(typeof(Widgets));
  
http.Start();  
Console.WriteLine($"HTTP Server is listening on {http.ListeningPrefixes[0]}");  
Console.ReadKey();

Now we have a new endpoint in our application.

Conclusion

Sisk is a really exciting HTTP server, and while it’s certainly not the first attempt at an independent HTTP server implementation, it is a welcome addition to the .NET ecosystem. If you need a lightweight HTTP server implementation without all of what ASP.NET Core offers, then Sisk might be for you. Remember, though, this HTTP server is independent of the ASP.NET Core ecosystem, so be prepared to write your integrations or rely on external implementations.

This post only begins to scratch the surface of what Sisk provides, so I suggest you check out the GitHub repository and documentation to see if it’s right for you.