In my previous post, I gave an overview of NancyFX, an open source and community supported web framework for ASP.Net Core. Now I want to focus on how it compares to Web API, the de facto standard in ASP.Net Core.
Nancy and Web API have a lot in common. Both are web frameworks that allow developers to create HTTP services and provide support for routing, request/response mapping, error handling, cookie management, and more. And while they allow developers to accomplish many of the same tasks, they go about it in different ways. Let’s take a look at some of the similarities and some of the differences.
My previous post covered setting up a Nancy application, so let’s see how the same thing would be done in Web API.
1. Web API is a part of ASP.Net Core so there are no extra packages needed in your application’s csproj file.
2. Telling the application to use Web API requires a couple updates to the Startup class. Here we are adding MVC to the list of services and telling the application to use MVC. We’re also defining a single route, and specifying a controller and an action that this should map to. The template is empty, so this will match the root URL of our application.
3. And finally we create a controller and an action by inheriting from the Web API provided Controller class and adding a method. The names of these should correspond to the route we defined in Startup. The HttpGet attribute above the method tells Web API that this method should be used for GET requests only. The Ok() return value tells Web API that this response should be sent with a 200 OK status.
This syntax is not quite as concise as that of Nancy, but it’s still straightforward. And as in Nancy, classes that inherit from the Web API provided Controller class will be discovered automatically on startup, so there’s no need to register them or put them in a particular place.
Modules, Controllers, and Routing
As you can see in our simple Hello World app, Web API actions are defined as methods within the controller class, and http methods (and optionally routes) are defined by adding attributes to these methods. Nancy, by contrast, defines routes, actions, and verbs together in the constructor of a module. Our simple app in the previous post only used the Get() method to define an HTTP GET action, but Nancy provides Post(), Put(), Delete() etc. to handle other verbs. The first parameter to this method is the route to match on, and the second argument is a lambda expression which defines the action to be executed when the route is matched. Nancy wraps anything returned in a response automatically, so there’s no need to wrap return values in a web response, and generally no need to worry about what type is being returned.
Both Web API and Nancy provide powerful route matching engines, which support regular expressions, optional parameters, value capture, type constraints and more. The usage is slightly different between the two frameworks, but not substantially.
In this example our controller is saving a new user with a post method. Take note that the input view model has been added as a parameter to the Save method. Web API will automatically try to map the incoming JSON request body to a UserViewModel object. At the end of the method we check if the user was saved correctly and return a 200 OK if it was, or a 500 ERROR otherwise.
This is different from Nancy, which uses a dynamic type when dealing with input parameters. This alleviates the need for explicit mapping at the expense of strong type checking. One method is not necessarily better than the other, but both have advantages.
View Engines and Templates
Web API works with the Razor view engine out of the box, so there is nothing to add or configure to start working with Razor templates. Simply place your cshtml files in a location that Web API is expecting and use the View method in your action to return a view. Additionally, Both Nancy and Web API provide overloads to assist in proper view retrieval via naming conventions.
If you’re creating a strictly back-end application, such as a set of microservices, then none of this view engine business matters. But if your application does require one you will find that you almost always outgrow the Super Simple View Engine provided by Nancy. Unless you are sure that your UI needs will stay simple it’s a safe bet to setup a third party view engine from the beginning. This is a little bit of a headache compared to Web API, where Razor is supported out of the box, but the setup is one-time only and fairly straightforward.
Traditional ASP.Net Web API development was very different from NancyFX. It favored explicit configuration and required quite a bit of bootstrapping code. But the ASP.Net Core team seems to have taken a lot of cues from the successful open source framework. Many of the “convention of configuration” features of Nancy are present in the new Web API framework, and so are other classic Nancy features, such as built-in dependency injection, effortless http response building, and seamless view engine integration.
That being said, there are some key differences to consider before adopting one framework or the other. Nancy’s “happy path” requires almost zero setup, but deviating from that setup can require lengthy (and often poorly-documented) configuration code. Additionally, Nancy’s constructor route definition is compact and readable for modules with a few, small actions, but the readability benefit is lost in large, complicated modules. Also, the DynamicDictionary input parameter is a great way to get around tedious mapping code, but the loss of type safety can lead to hard to track down bugs in large, complicated models.
I hope this has given you some things to think about when you’re starting your next ASP.Net Core project, and if Nancy looks like it could suit your needs, you should definitely give it a shot.