.Net Core and NancyFX: can writing a WebApi get any simpler?

Last Thursday I attended a Meetup hosted by my friends of @MsCodersMadrid in Madrid where, thanks to @snavarropino, I learned a bit about the NancyFX open source framework.

I really couldn’t believe my eyes when I saw how simple it is to use NancyFX to write a Web API. Two of the things that got my attention were: the out of the box content negotiation and zero configuration dependency injection.

What are we waiting for? Lets’s put in the mix .Net Core and NancyFX and ask ourselves: can a WebApi get any simpler?.

Steps:

1. Create the application


Open a command prompt and run

1    md nancyfx.sample
2    cd nancyfx.sample
3    dotnet new
4    dotnet restore
5    code .

2. Replace the contents of project.json


Replace the contents on project.json file. Be sure to include the references to Microsoft.AspNetCore.Owin and Nancy

 1{
 2  "dependencies": {
 3    "Microsoft.NETCore.App": {
 4      "version": "1.1.0-preview1-001153-00",
 5      "type": "platform"
 6    },
 7    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
 8    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
 9    "Microsoft.AspNetCore.Owin": "1.0.0",
10    "Nancy": "2.0.0-clinteastwood"
11  },
12  "tools": {},
13  "frameworks": {
14    "netcoreapp1.1": {
15      "imports": [
16        "dotnet5.6",
17        "dnxcore50",
18        "portable-net45+win8"
19      ]
20    }
21  },
22  "buildOptions": {
23    "debugType": "portable",
24    "emitEntryPoint": true,
25    "preserveCompilationContext": true
26  },
27  "runtimeOptions": {
28    "configProperties": {
29      "System.GC.Server": true
30    }
31  },
32  "publishOptions": {},
33  "scripts": {},
34  "tooling": {
35    "defaultNamespace": "WebApplication"
36  }
37}

3. Replace the contents of Program.cs


Let’s host the Web API with AspNetCore

 1using System.IO;
 2using Microsoft.AspNetCore.Hosting;
 3
 4namespace WebApplication
 5{
 6    public class Program
 7    {
 8        public static void Main(string[] args)
 9        {
10            var host = new WebHostBuilder()
11                .UseKestrel()
12                .UseContentRoot(Directory.GetCurrentDirectory())
13                .UseIISIntegration()
14                .UseStartup<Startup>()
15                .Build();
16
17            host.Run();
18        }
19    }
20}

4. Add a Startup.cs


This one-liner hooks NancyFX to our application.

 1using Microsoft.AspNetCore.Builder;
 2using Nancy.Owin;
 3
 4namespace WebApplication
 5{
 6    public class Startup
 7    {
 8        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 9        public void Configure(IApplicationBuilder app)
10        {
11            app.UseOwin(x => x.UseNancy());
12        }
13    }
14}

5. Create a service to return some random message


Add a new file (i.e BaconIpsumService.cs) to hold the application logic and add the following sample content

 1using System.Net.Http;
 2using System.Threading.Tasks;
 3
 4namespace WebApplication
 5{
 6    public class BaconIpsumMessage
 7    {
 8        public string Body {get; set;}
 9    }
10
11    public interface IBaconIpsumService
12    {
13        Task<BaconIpsumMessage> GenerateAsync();
14    }
15
16    public class BaconIpsumService : IBaconIpsumService
17    {
18        public async Task<BaconIpsumMessage> GenerateAsync()
19        {
20            using (var client = new HttpClient())
21            {
22                var message = new BaconIpsumMessage();
23                // Post the message
24                message.Body =  await client.GetStringAsync(
25                    $"https://baconipsum.com/api/?type=meat-and-filler");
26
27                return message;
28            }
29        }
30    }
31}

5. Create a NancyFX module to host the WebAPI


Create a new file (i.e BaconIpsumModule .cs) to hold the routes and actions for the Web API

 1using Nancy;
 2
 3namespace WebApplication
 4{
 5    public class BaconIpsumModule : NancyModule
 6    {
 7        public BaconIpsumModule(IBaconIpsumService baconIpsumService)
 8        {
 9            Get("/", args => "Super Duper Happy Path running on .NET Core");
10
11            Get("/baconipsum", async args => await baconIpsumService.GenerateAsync());
12        }
13    }
14}

The first route returns a string and the second one calls our service and returns a BaconIpsumMessage instance (And yes! NancyFX supports async too!).

Also note that the module requires an instance of IBaconIpsumService in the constructor but don’t worry because NancyFX will inject it for you without any special configuration or registration!

6. Run and test the application


Run the following commands

1dotnet restore
2dotnet run

Navigate to http://localhost:5000 and the browser should show the message: Super Duper Happy Path running on .NET Core

Navigate to http://localhost:5000/baconipsum and because of automatic content navigation NancyFX will try to find a view to display the BaconIpsumMessage which we didn’t register and therefore results in an internal server error:

Now call the same url: http://localhost:5000/baconipsum using postman and you’ll get the expected json:

Get a copy of the code here: https://github.com/cmendible/dotnetcore.samples/tree/main/nancyfx.sample

Hope it helps!


The Value of Online Influencer
.NET Core, Roslyn and Code Generation
comments powered by Disqus