NancyFX (Or Nancy, FX stands for framework), is a super lightweight web framework that can be used to spin up minimalist API’s in no time at all. It’s mostly seen as an alternative to Web API when you don’t need all the plumbing and boilerplate work of a full Web API project. It also has a lot of popularity with NodeJS developers that are used to very simple DSL’s to build API’s.
Getting Started
When creating a new project, you want to create a .net core web project but make sure it’s created as an “empty” application. If you select Web API (Or MVC) it brings along with it a ton of references and boilerplate code that you won’t need when using Nancy.
You will need the Nancy Nuget package so run the following from your package manager console. At this point in time the .net core able Nancy is in Pre-Release, so at the time of writing, you will need the pre flag when installing from Nuget.
Install-Package Nancy -Pre
In your startup.cs you need to add a call to UseNancy in the Configure method. Note that any other handler in here (Like AddMVC) may screw up your pipeline, especially when it comes to routing. If you are intending to use Nancy it’s probably better to go all in and not try and mix and match frameworks.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseOwin(x => x.UseNancy()); }
If you have issues with the line “UseOwin” then you will need to install the Owin package.
Install-Package Microsoft.AspNetCore.Owin
Instead of creating a class that inherits from “Controller” as you normally would in Web API, create a class that inherits from “NancyModule”. All your work is then actually done in the constructor, which may seem a bit weird at first but when you are building a tiny API it actually becomes nice to keep things to a minimum. Our NancyModule that we will use for the tutorial looks a bit like this
public class HomeModule : NancyModule { public HomeModule() { Get("/", args => "Hello World"); Get("/SayHello", args => $"Hello {this.Request.Query["name"]}"); Get("/SayHello2/{name}", args => $"Hello {args.name}"); } }
It should be pretty self-explanatory. But let’s go through each one.
- When I go to “/” I will see the text “Hello World”.
- When I go to “/SayHello?name=wade” I will see “Hello wade”
- When I go to “/SayHello2/wade” I will see “Hello wade”
As you can probably see, Nancy is extremely good for simple API’s such as lookup type queries.
Model Binding
While you can stick with using dynamic objects, model binding is always a nice addition. Below is an example of how to model bind on a POST request.
public class HomeModule : NancyModule { public HomeModule() { Post("/login", args => { var loginModel = this.Bind<Models.LoginModel>(); return $"Logged In {loginModel.Username}"; }); } }
Using Postman I can send a request to /login as a form encoded request, and I can see I get the correct response back :
Nancy also recognizes different body types. If you send the request as JSON (With the appropriate header of “Content Type:application.json”), Nancy will still be able to bind the model.
Before and After Hooks
Before and after hooks are sort of like MVC filters whereby you can intercept the request before and after your Nancy Module has run. Note that this is still part of the .net core middleware pipeline so you can still add custom .net core middleware to your application along side Nancy hooks.
An important thing with hooks is that they are per module. They live within the module and are only run on requests routed to that module, any requests that land on other modules don’t run the before hook. The hook itself tends to point to a method elsewhere, so in the end it works out a bit like a controller attribute.
There are two ways a hook can handle a request. Here’s one way :
public HomeModule() { Before += context => { //Do something with the context here. return null; }; Get("/", args => "Hello World!"); }
If a hook returns null as above, code execution is passed down to the matching route. For example, if you are checking the existence of a particular header (API key or the like), and it’s there, then returning null simply allows execution to continue. Compare this to the following :
Before += context => { if (!context.Request.Headers.Keys.Contains("x-api-key")) { return Response.AsText("Request Denied"); } else { return null; } };
In this example, if our header collection doesn’t contain our API key (Weak security I know!), we return a response of “Request Denied” and execution ends right there. If the header is there, we continue execution.
View Engine
While Nancy predominately is used for lightweight API’s, there is an inbuilt view engine and you can even get an addon that allows for Razor-like syntax – In fact it’s pretty much identical to Razor. The actual package can be found here. Unfortunately, at this time the view engine has a dependency on the full .net framework so cannot be used in a web application targeting .net core.
Static Content
Nancy by default won’t serve static content. It does have its own way of dealing with static content and various conventions, but I actually prefer to stick with the standard ASP.net core middleware for static files. This way it short-circuits Nancy completely and avoids going down the Nancy pipeline. For that you can install the following nuget package :
Install-Package Microsoft.AspNetCore.StaticFiles
In the Startup.cs class in the Configure method, add a call to UseStaticFiles like so :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseStaticFiles(); app.UseOwin(x => x.UseNancy()); }
Place all your static content in the wwwroot (CSS, Images, Javascript etc), and you will now be able to have these files served outside the Nancy pipeline.
Everything Else
Nancy has it’s own documentation here that you can take a read through. Some of it is pretty verbose, and you also have to remember that not all of it is applicable to .net core. Like the static content section above, there may be an existing solution with .net core that works better out of the box or is easier to configure. As always, drop a comment below to show off your new project you built in Nancy!