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

by Carlos Mendible on 16 Jan 2017 » dotNetCore

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

    md nancyfx.sample
    cd nancyfx.sample
    dotnet new
    dotnet restore
    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

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0-preview1-001153-00",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
    "Microsoft.AspNetCore.Owin": "1.0.0",
    "Nancy": "2.0.0-clinteastwood"
  },
  "tools": {},
  "frameworks": {
    "netcoreapp1.1": {
      "imports": [
        "dotnet5.6",
        "dnxcore50",
        "portable-net45+win8"
      ]
    }
  },
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },
  "publishOptions": {},
  "scripts": {},
  "tooling": {
    "defaultNamespace": "WebApplication"
  }
}

3. Replace the contents of Program.cs


Let’s host the Web API with AspNetCore

using System.IO;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

4. Add a Startup.cs


This one-liner hooks NancyFX to our application.

using Microsoft.AspNetCore.Builder;
using Nancy.Owin;

namespace WebApplication
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app)
        {
            app.UseOwin(x => x.UseNancy());
        }
    }
}

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

using System.Net.Http;
using System.Threading.Tasks;

namespace WebApplication
{
    public class BaconIpsumMessage
    {
        public string Body {get; set;}
    }

    public interface IBaconIpsumService
    {
        Task<BaconIpsumMessage> GenerateAsync();
    }

    public class BaconIpsumService : IBaconIpsumService
    {
        public async Task<BaconIpsumMessage> GenerateAsync()
        {
            using (var client = new HttpClient())
            {
                var message = new BaconIpsumMessage();
                // Post the message
                message.Body =  await client.GetStringAsync(
                    $"https://baconipsum.com/api/?type=meat-and-filler");

                return message;
            }
        }
    }
}

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

using Nancy;

namespace WebApplication
{
    public class BaconIpsumModule : NancyModule
    {
        public BaconIpsumModule(IBaconIpsumService baconIpsumService)
        {
            Get("/", args => "Super Duper Happy Path running on .NET Core");

            Get("/baconipsum", async args => await baconIpsumService.GenerateAsync());
        }
    }
}

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

dotnet restore
dotnet 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/master/nancyfx.sample

Hope it helps!