Creating Microservices Using NancyFX

In the IoT world of embedded devices, small is beautiful and small doesn't come much better than the NancyFX Web framework.

Nancy is a small, exceptionally easy to use REST and service framework.

You can use it in place of ASP.NET MVC; you can use it on its own in a self-hosting environment, just as you might do if you're deploying applications using NodeJS for example.

Nancy's strength, however, comes from far more than just its tiny size. Into the default install, it manages to pack a full IoC container, a built-in testing framework, the ability to build some very complex routing rules, and a modular architecture that makes it amazingly easy to plug in extra features with little or no effort.

Perhaps one of the best things about Nancy, however, especially when it comes to the "Internet Of Things," is that it runs with no modification under MONO. In fact, Nancy is so successful in this respect that I've built and tested Nancy-based applications fully on a Windows system, and then just copied the EXE and resultant DLLs to a target Linux server running MONO and had everything run immediately and with 100% success.

Nancy runs perfectly on small embedded boards such as the Arduino and RaspberryPi, meaning if you're in a constrained environment where you can't install a full-blown Web server such as Apache but you need more configuration possibilities than NginX+PHP gives you, NancyFX is a perfect choice.

Let's Build a Server….

As is the norm for this column, launch Visual Studio and start a console mode project.

Head straight to NuGet and install Nancy and Nancy.Hosting.Self:

Nancy1
Figure 1: Nancy NuGet packages

Once these two packages are added, make sure your Program.cs file looks as follows:

using System;
using Nancy.Hosting.Self;

namespace NancyMicroservice
{
   class Program
   {
      static void Main()
      {
         var url = "http://127.0.0.1:9000";

         using(var host = new NancyHost(new Uri(url)))
         {
            host.Start();
            Console.WriteLine("Nancy Server listening
               on {0}", url);
            Console.ReadLine();
         }

      }

   }
}

If you press F5 and run your application, Nancy now will start up, and start listening on the address provided in the URL.

Nancy2
Figure 2: Our server runs.

For now, however, you have no routes, so everything you try to browse to will give you a 404 courtesy of The Oatmeal.

Nancy3
Figure 3: However, we have no routes, so all we get is a 404.

It's at this point that you get to see some Nancy magic in play.

What's in a Module?

If your server is still running, press Return to get it to quit, and then switch back to VS.

Unlike most frameworks you might be familiar with, Nancy uses what it calls "Modules" to provide its routing.

A module is a class that's derived from "NancyModule" and is automatically found and used without you doing any more than writing a simple class.

Add a new class to your project and call it "RootRoutes.cs". Then, make sure it has the following code in:

using Nancy;

namespace NancyMicroservice
{
   public class RootRoutes : NancyModule
   {
      public RootRoutes()
      {
         Get["/"] = parameters =>
         {
            return "Hello World";
         };

      }

   }
}

If you press F5 now, and point your browser at http://127.0.0.1:9000, you should see "Hello World" appear.

Nancy4
Figure 4: "Hello World", Nancy Style

One of Nancy's biggest strengths is its ability to return and manipulate JSON with ease. Add another route to the class you just created, so that your file now looks as follows:

using Nancy;

namespace NancyMicroservice
{
   public class RootRoutes : NancyModule
   {
      public RootRoutes()
      {
         Get["/"] = parameters =>
         {
            return "Hello World";
         };

         Get["jsontest"] = parameters =>
         {
            var test = new {Name = "Peter Shaw",
               Twitter = "shawty_ds",
               Occupation = "Software Developer"};

            return Response.AsJson(test);
         };

      }

   }
}

If you run this now, and browse to http://127.0.0.1:9000/jsontest, you should see something like the following. (Don't worry if yours is not identical; I have a Chrome plugin called 'JsonView' installed. As long as you get JSON returned, all is okay.)

Nancy5
Figure 5: Nancy does JSON

Nancy also can do XML. In fact, Nancy has a full "Content Negotiation" algorithm built into it, and if you change your route handler so that it simply just returns the "test" object in the previous code, Nancy will actually try to figure out what the best format to return is.

If you try this in the browser, for example, with just the "test" object and no 'AsJson' call, you'll actually get a 500 server error.

Why?

Well, because the browser will request HTML, and you currently don't have a HTML view set up to format and return your "test" object back to the browser. If, however, you test the URL using a dedicated tool such as Fiddler or Postman, you'll quickly see that changing the request MIME Type between "application/json" and "application/xml" will cause Nancy to automatically send you the correct type.

Nancy also comes with a built-in View Engine called SSVE (Super Simple View Engine), and if you create a "Views" folder in your application, and then make sure that folder is always copied to your output folder, Nancy will automatically search in that folder for any HTML files that have the same name as your object.

In our sample above, however, we're using an anonymous object, so creating a view won't work because our object has no type name.

Going back to our routes, there's one thing that always gets me about Nancy and that's how all your route code is always in the constructor. I personally like to be able to use the code folding built in to Visual Studio, and that doesn't always work reliably when you have a large constructor defining a lot of routes.

For this reason, I usually like to create my "Modules" in the following way:

using Nancy;

namespace NancyMicroservice
{
   public class RootRoutes : NancyModule
   {
      public RootRoutes()
      {
         Get["/"] = Index;
         Get["jsontest"] = JsonTest;
      }

      private dynamic Index(dynamic parameters)
      {
         return "Hello World";
      }

      private dynamic JsonTest(dynamic parameters)
      {
         var test = new { Name = "Peter Shaw",
            Twitter = "shawty_ds",
            Occupation = "Software Developer" };

         return Response.AsJson(test);
      }

   }
}

For me, this makes my code much neater and allows me to hide methods I'm not working on, this is of course just personal preference and however you manage it, is entirely up to you.

Routing Parameters

By now, you've probably spotted the "parameters" entry in both pieces of code.

Nancy again magically wires all of this up. You don't need to pre-define template routes as you do in ASP.NET MVC.

You can simply just define your route, directly in your constructor then use the "parameters" (or whatever you name it) variable to access those route segments.

Add another route to your class, so that it now looks as follows:

using System;
using Nancy;

namespace NancyMicroservice
{
   public class RootRoutes : NancyModule
   {
      public RootRoutes()
      {
         Get["/"] = Index;
         Get["jsontest"] = JsonTest;
         Get["hello/{name}"] = HelloName;
      }

      private dynamic HelloName(dynamic parameters)
      {
         var name = parameters.name;

         return String.Format("Hello there {0}", name);
      }

      private dynamic Index(dynamic parameters)
      {
         return "Hello World";
      }

      private dynamic JsonTest(dynamic parameters)
      {
         var test = new { Name = "Peter Shaw",
            Twitter = "shawty_ds",
            Occupation = "Software Developer" };

         return Response.AsJson(test);
      }

   }
}

If you run your server now, and point your browser at http://127.0.0.1:9000/hello/shawty, you should see:

Nancy6
Figure 6: Nancy with route parameters

Anything enclosed in {} in a URL route will be available this way without any extra work.

But what about posting data, I hear you all say?

Well, for this, Nancy has automatic binding available, and as long as it can find a parameter or parameters that match the fields in your object, it will automatically populate the object for you.

Nancy will look on the URL, in the request headers, and in the payload body to find matches. It will even decode the body correctly in most cases, irrespective of you sending JSON or key value pairs, and most of the time it will get this right, again without you having to do any kind of extra configuration.

Add a new class to your project, called "Person.cs", as follows:

namespace NancyMicroservice
{
   public class Person
   {
      public string Name { get; set; }
      public string Twitter { get; set; }
      public string Occupation { get; set; }

   }
}

Then, add a new route handler to your "RootRoutes.cs" file, so that it now looks as follows:

using System;
using Nancy;
using Nancy.ModelBinding;

namespace NancyMicroservice
{
   public class RootRoutes : NancyModule
   {
      public RootRoutes()
      {
         Get["/"] = Index;
         Get["jsontest"] = JsonTest;
         Get["hello/{name}"] = HelloName;
         Post["posttest"] = PostTest;
      }

      private dynamic PostTest(dynamic parameters)
      {
         var myPerson = this.Bind<Person>();

         return String.Format("Hello there {0} with
            twitter handle {1} who works as a {2}",
            myPerson.Name, myPerson.Twitter,
            myPerson.Occupation);
      }

      private dynamic HelloName(dynamic parameters)
      {
         var name = parameters.name;

         return String.Format("Hello there {0}", name);
      }

      private dynamic Index(dynamic parameters)
      {
         return "Hello World";
      }

      private dynamic JsonTest(dynamic parameters)
      {
         var test = new { Name = "Peter Shaw",
            Twitter = "shawty_ds",
            Occupation = "Software Developer" };

         return Response.AsJson(test);
      }

   }
}

If you then post some data to this route and name your three parameters as 'Name', 'Twitter', and 'Occupation', Nancy will pick them up and use them:

Nancy7
Figure 7: Testing the post acceptor using Fiddler

You'll see, when you look at the response, that Nancy returns the data it found in the post request:

Nancy8
Figure 8: The response returned by our Post-test in Fiddler

There's a whole lot more to learn than just what I've presented here in this post, but if you need to build a simple REST-based server interface for your IoT devices, NancyFX fits the bill perfectly.

I've deployed solutions to RaspberyPi (for monitoring weather stations) and Arduino-based devices, and I've even used it for full-scale Web applications with authentication and regular security practices. Nancy scales, no matter what you deploy it on. I've recently written a book on NancyFX that will be available in the not too distant future in the Succinctly free eBook range from Syncfusion. If you want to go deeper and really find out what Nancy can do, keep your eye open for it hitting the interwebs.

.NET giving you .NOT? Can't find a routine or API to finish that last little requirement in your project? Drop me a comment below and I'll see what I can do to help.



About the Author

Peter Shaw

As an early adopter of IT back in the late 1970s to early 1980s, I started out with a humble little 1KB Sinclair ZX81 home computer. Within a very short space of time, this small 1KB machine became a 16KB Tandy TRS-80, followed by an Acorn Electron and, eventually, after going through many other different machines, a 4MB, ARM-powered Acorn A5000. After leaving school and getting involved with DOS-based PCs, I went on to train in many different disciplines in the computer networking and communications industries. After returning to university in the mid-1990s and gaining a Bachelor of Science in Computing for Industry, I now run my own consulting business in the northeast of England called Digital Solutions Computer Software, Ltd. I advise clients at both a hardware and software level in many different IT disciplines, covering a wide range of domain-specific knowledge—from mobile communications and networks right through to geographic information systems and banking and finance.

Related Articles

Comments

  • Awesome post

    Posted by Guruprasad on 03/17/2016 09:15pm

    The best, I can say. Its really beautiful and you have explained it in a very efficient way. Thank you for this.

    Reply
  • This should be C# nothing more

    Posted by L Mohan Arun on 11/02/2015 03:24am

    "in place of ASP.NET MVC?" Dont invent new frameworks this framework that framework What needs to be invented is "IoT framework for C#" "IoT framework for C++" "Java framework for low power always on devices" For that, you need to tackle device id, security, and able to retract permissions assigned to a household IoT enabled device. You should be able to program IoT using any programming language, C++, Java (Kindle uses this), and C# / Visual Basic whatever.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date