Showing posts with label NancyFx. Show all posts
Showing posts with label NancyFx. Show all posts

Sunday, January 29, 2017

"Microservices in .NET Core" has landed

My new book "Microservices in .NET Core  - with examples in Nancy" has been published. It's been available as an early access ebook for a long time, but now the final paper book and the final ebook is available.


This book is very much based on experience from working of real microservices systems. While the examples in the book are not lifted directly from any particular system they are inspired by real world systems. My rule has been that all the examples demonstrate something that could have been in one or more of the systems I have experience with.

With this book I have tried to show two things:

    1. How to design a microservices system.
    2. How to build such a system using a lightweight .NET based tech stack.

All but one chapter reflect these two levels, in that they start off explaining an aspect of designing a microservice system, and then go on to show how to implement it using my .NET tech stack of choice. This should help make clear which parts make sense regardless of tech stack and which are tech specific. At the end of the book  you should have the tools to both design a microservice system and implement it, as we have covered subjects like how to decide what belongs in which microservice, where data resides, how microservices collaborate, how to test such a system, how to make it robust and how gain insights into how it is doing in production.

The tech stack I use in the book is based on .NET Core, Microsoft's new cross platform version of .NET. On top of .NET Core I use the Nancy web framework and OWIN middleware, which forms a powerful yet simple stack. To compliment this I use various other OSS libraries where appropriate, like Polly and Dapper. The guiding principle in all the tech choices is that they should be simple to use - make the simple stuff simple, while also allowing to do more complex stuff without unwarranted hassle.

You can find the table of contents and a couple of sample chapter on the books page at Manning. 
Also, if you are interested in these things, I have a 3 day course around these things available.

Saturday, August 30, 2014

Using Nancy.Linker with Razor Views

First things first: I recommend that you use Nancy.Linker to generate link in the route handler not the view code, as described in my last post. If you insist on generating the links in the view code here is how to make Nancy.Linker work with Razor views.

Firstly you need to pass an instance on IResourceLinker and the NancyContext to your view. This works just like passing any other object from the handler to the view  - in your Nancy module you have your route handler pass the IResoureLinker and NancyContext objects as part of the model to the view you want to render:




The NancyContext must  passed along with the IResourceLinker, since Nancy.Linker needs it to generate links. Once you've done this you are almost ready to use Nancy.Linker in your Razor code, but first you need a little bit of web.config gymnasitcs. This is because IResouceLinkker returns System.Uri objects, which Razor does not know about unless you tell it where to look. To tell Razor, add this to your web.config:



Refer to the Nancy documentation for a proper explanation of this.
Having added the web.config snippet you can go ahead and use Nancy.Linker to generate links in the Razor code:



That's all folks!

Sunday, July 27, 2014

Using Nancy.Linker with Views

TL;DR

You have two options: 
  • The simplest is to use Nancy.Linker in your route handler to generate the links needed in the views, put them on the view model and pass the view model to the view as usual. 
  • The other is to pass IResourceLinker to the view and allow it to generate links as needed. For this to work you may need a little bit of web.config'ing to make Razor play nice. 
This post shows the former.

Nothing New

In the last post I introduced Nancy.Linker, showed how to use it to create links to named routes and place them on a model object returned by a Nancy route handler.

In essence; given this module:


This route handler will return a model with a link to the route in the module above in either XML, JSON or whatever other format you have support for in your application:


(how the format is chosen, and which are supported is another story)
Now, if you want to show that link in a view, you just have to add one line the to handler and - of course - view code. The handler becomes:


Assuming you are using Razor for your views the bar.cshtml view can simply be:


There you have it. Just use Nancy.Linker the same as when returning data, point to the view from the handler and use the generated link as any other string passed to a view.

This is the approach I'd recommend, but in the next post I will show how to use IResourceLinker in Razor code.

Saturday, July 5, 2014

Nancy.Linker

TL;DR

Nancy.Linker is a small library for creating URIs for named routes in Nancy application that I released to NuGet the other day.

Purpose of Nancy.Linker

The problem Nancy.Linker solves is to allow your application code to create URIs pointing to endpoints in your Nancy application without hardcoding the URI. Instead you refer to the endpoint by its route name and provide values for whatever route parameters the route expects. The library then returns you a suitable System.Uri.

Example

Let's consider a Nancy application with this module in it:


The module does nothing interesting, but bear with me. The thing to notice is that FooModule has all sorts of routes - a constant one, one with a simple parameter, one with a constraint on a parameter, one with a regex segment with a captured parameter, one with an optional parameter and one with a default value for an optional parameter. To read up on Nancy routing check out the docs.

Now let's assume another module needs to put links to endpoints in FooModule in its own response. It can do so by taking a dependency on IResoureLinker from Nancy.Linker and asking it to create the URIs:


which will produce a response containing a bunch of links back to the FooModule. For instance the call 


results in this string (assuming your application runs on http://www.nancyisawesome.com):


Getting Started

Just install Nancy.Linker from NuGet:


Nancy.Linker will take care of registering the IResourceLinker with your container, so modules can just go ahead a take a dependency on IResourceLinker.



Saturday, October 26, 2013

Supporting Single Sign On In Your Nancy Applications

In enterprise application the requirement for single sign on is common: Users are already authenticated against the domain controller - they don't want to jump through another authentication hoop to get access to your particular application. Setting this up in ASP.NET using WIF is some pretty easy web.config gymnastics and described elsewhere. The result of this setup is that the current principal on authenticated requests is a ClaimsPrincipal identifying the user in terms of the claims setup for him/her in the identity provided (e.g. your organizations Active Directory).
Below I show how to integrate the WIF authentication setup with your Nancy application - It doesn't take much, but lets run through it anyway. In fact only 2 small classes are needed. First we define a user type that implements the IUserIndentity interface expected by Nancy, by pulling the necessary information out of the current claims principal:

The second thing we need is set the current user on the NancyContext for each incoming request. We do this by hooking into Nancys request pipeline with a Before hook. We can do this directly in our Nancy applications bootstrapper or in a separate type implementing IApplicationStartup (Nancy automatically finds and executes these at application startup). This is how it's done with the IApplicationStartup approach:

That's it. Now your modules can start using the Context.CurrentUser and take advantage of Nancys authorization helpers.

Update: As kindly pointed out by Damian Hickey this will not work if you host your Nancy application on OWIN. So to be clear: I have only tested this when hosting on ASP.NET. The fact that it will not work on OWIN, means that the approach has the drawback that it leaks knowledge of the host to the application level. Specifically to the SetUser class.

Sunday, September 29, 2013

The "Instant Nancy Web Development" Book

After a quick six month writing and editing process my Nancy book is published. It's available as e-pub, mobi, pfd and dead trees via the publishers site as well as Amazon, Amazon UK, and Safari.

What's it about?
Well, it about the Nancy web framework. Nancy is an awesome .NET based web framework that focuses on being both easy and fun to work with. Nancy lends itself to writing highly testable web application with simple, concise and readable code. Who doesn't want that?
The book starts from the very basics of getting Nancy up and running, but quickly moves into more interesting areas including dependency injection, hosting, content negotiation, authentication, async processing and more. Check out the full table of contents at the publishers site.

Who's it for?
The reader I've had in mind is a .NET oriented backend developer who values clean testable code and who is curious about what all the fuss around Nancy is about. It's a short book, so it is also a quick read and a quick way to get into a whole bunch of Nancy topics.

Why did I write it?
There are a number of reasons I wrote this book. I'll only talk about a few of them here. Starting from the egotistical side @thecodejunkie nailed it on jabbr: "It's about bragging rights" :-) I have to admit there is truth in that.

Another reason is that I really think Nancy deserves having a light shone on it, and I believe a book is one way to do that.
I believe a book can reach another segment of developers and architects than Github wiki, blogs and demo applications. The book hopefully wont be the end stage for those developers and architects, but rather the gateway to the Github wiki and even the Nancy source code, which is so readable that it actually is a fine source to learn Nancy from.
I also think a book can lend a sense of legitimacy to an OSS, which may help a little bit with getting through the gate into enterprises. @cranialstrain expressed this well on twitter the other day.

Thursday, June 27, 2013

My Nancy Talk from NDC

The video of the talk I did on Nancy at NDC is out.

The talk me writing some Nancy code, talking a lot about Nancy and at the end I have a simple todo application.

Enjoy!


Monday, March 18, 2013

Hello Nancy World in F#

As you may noticed (if you follow this blog or go to the same conferences as me) I really like the Nancy web framework. So naturally, since I've decided to finally learn F# properly, I threw together a hello world Nancy app in F#. It's very simple; the complete code is listed below. All I did was create an F# console application, install the Nancy and Nancy.Hosting.Self NuGet packages and type in this code, which will return the string "Hello" if you point your browser to "http://localhost:8888/nancy/":



So what's going in that code? Fist thing to notice is the type HelloModule which inherits NancyModule. On start up Nancy will pick up all NancyModules and run their constructor. In it's constructor HelloModule sets up a single route, "/", and tells Nancy what to do on a HTTP GET to that route, namely to execute a lambda that always returns "Hello". Lastly, since this is self hosted, there is a bit of setup in the "main" function: A Nancy host is instantiated, told where to listen for requests and started. This will make the Nancy self host start up Nancy and start listening for requests. That's it. Short and sweet.

Sunday, December 16, 2012

Speaking at Warm Crocodile

In about a month from now I'll be at Warm Crocodile conference in Copenhagen. While there I'll be giving two talks, both on the Thursday. The titles and abstracts are:

  • Introduction to Nancy: Nancy is a lightweight .NET web framework. It provides an easy to use, to-the-point alternative to the most commonly used .NET web frameworks. Nancy does not try to be everything to everyone. But it does try to be the super-duper-happy path to web development on .NET and Mono. Come get introduced to Nancy, and judge for yourself.
  • Layers Consider Harmful : Layers are killing us. All the time. They are killing our communication. They are killing our speed. They are killing the others speed as well. We need to do better. Which we can. I'll tell why layers are killing us. I might even tell you something about how to do better.
Warm Crocodile is a new conference organized by, among others, Daniel Frost, who e.g. has been one half of making Community Cph. happen. If Warm Crocodile can take that fun, sharing and welcoming atmosphere of Community Day and combine that with the high quality content it the impressive international speaker line up promises, it'll an absolutely great couple of days-

Hope to see to you there for some geeking out and a good discussion!

Sunday, November 18, 2012

Thursday, May 10, 2012

Slides from my Community Day Copenhagen 2012 Talk

I did a talk on "alternative" .NET web frameworks, because I think it's important to realize that there are serious alternatives to ASP.NET - even in .NET-land. Anyway here are the slides:


Tuesday, December 20, 2011

Slides from ANUG talk on Nancy

I did a talk on Nancy a week ago in the Aarhus -NET User Group. And in my own humble and unbiased opinion it went quite well :-) So I thought I'd share the slides with you - although they probably only make semi-sense without the talk to go along. Anyway here they are; enjoy.


Tuesday, November 8, 2011

Frictionless .NET Web App Development with Nancy Part IV - Hosting

Continuing my URL shortener sample (part I, II, III), I'll talk about one the things Nancy does quite differently from your average web framework: Nancys concept of hosting. At this point you may be thinking serves or clouds or storage etc, but that's not exactly what Nancy hosting is about.

Nancy Hosting
Nancy hosting is about which stack Nancy runs on top of. Such stacks include ASP.NET, WCF, OWIN, and self hosting. That means that a Nancy app can be run on top of any of those four hosts. You decide. So if you have an existing ASP.NET/IIS setup you can use it to run Nancy, if you have a WCF setup already you can use that.

The two last hosts may need a bit of introduction:

OWIN is Open Web Interface for .NET, which is an attempt to create a common interface between web frameworks and web servers. Currently it's not implemented by that many web servers, but could potentially allow web frameworks and the apps built on them to be move unchanged from one web server to another. One example of an OWIN compliant web server is Kayak, which can run on Mono. Combining these things means that our Nancy app can run on a stack of Nancy/Hosting.OWIN/Kayak/Mono/Linux. In other words a web app written in C# running on OSS all the way down. Who'd have thunk!

Self hosting is another interesting option: Self hosting means running a Nancy app in any .NET or Mono executable. This means that you can slap a web interface onto a desktop app or a windows service. Both of these possiblities are very interesting IMO.

Multiple Hosts - One Code Base
In the URL shortener sample I'd like to use the same application in two different settings: In a stand alone executable (just for kicks) and in ASP.NET stack. To do that I add two projects to my solution, one for each host:


First lets look at bit closer at the ASP.NET hosting project. I.e. the one called ShortUrlWebApp. It's simply an empty web project, as created by Visual Studio, with the Nancy.Hosting.Aspnet NuGet package and a project reference to ShortUrl added. Not one line of code wirtten. The project contains:


The Nancy.Hosting.Aspnet NuGet rewrites the web.config to make Nancy handle all incoming request. Nancy automatically picks up the Bootstrapper and Module in the ShortUrl assembly. That's all there is to running our url shortener on top of ASP.NET.

Second lets loot at the self hosting project. I.e. the one called ShortUrlDesktopApp. It's just a console application with a project reference to ShortUrl and the Nancy.Hosting.Self NuGet added:

In this case a little bit of work is needed in the program.cs - but not much, just instantiating and starting the NancyHost:

    1 namespace ShortUrlDesktopApp
    2 {
    3   using System;
    4   using Nancy.Hosting.Self;
    5   using ShortUrl;
    6 
    7   class Program
    8   {
    9     static void Main(string[] args)
   10     {
   11       ShortUrlModule artificiaReference;
   12       var nancyHost = new NancyHost(new Uri("http://localhost:8080/"));
   13       nancyHost.Start();
   14 
   15       Console.ReadKey();
   16 
   17       nancyHost.Stop();
   18     }
   19   }
   20 }

With this setup we can run the app on ASP.NET of from a console app. There is no difference in the browser and the application code is the same. This - IMO - is very cool indeed.

And the code is still on GitHub.

Monday, October 24, 2011

Frictionless .NET Web App Development with Nancy Part III - Introducing MongoDB

Continuing the URL shortener sample from thesse post: part I and part II, I'll go from (stupidly) storing the shortened URLs in a static variable, as was the case in the code in part I, to storing the shortened URLs in MongoDB. The reasons for choosing MongoDB for persistence in this sample (compared to the "traditional" NHibernate + SQL Server approach) are:
  • We will only store and retrieve one document at a time. Those are atomic operations in Mongo, so as far as this sample goes Mongo is fully consistent.
  • Mongo is simple to setup, and very simple to code against. For instance there is no O/R mapping layer at all.

In summary, Mongo is a nice frictionless option for this sample.

Enough talk, show me the code!

Decoupling interface from persistence
The first thing to do is to pull the persistence related code out of the Nancy module. We use the following couple of tests to drive that. They use a Moq mock to specify the interface to the persistence code; that is the UrlStore interface:

    1 namespace ShortUrlTest
    2 {
    3   using Xunit;
    4   using Nancy.Testing;
    5   using Moq;
    6   using ShortUrl;
    7 
    8   public class UrlStorageTest
    9   {
   10     private Browser app;
   11     private Mock<UrlStore> fakeStorage;
   12 
   13     public UrlStorageTest()
   14     {
   15       ShortUrlModule artificiaReference;
   16 
   17       //Given
   18       fakeStorage = new Mock<UrlStore>();
   19       app = new Browser(
   20               new ConfigurableBootstrapper(
   21                 with => with.Dependency(fakeStorage.Object)));
   22 
   23     }
   24 
   25     [Fact]
   26     public void app_should_store_url_when_one_is_posted()
   27     {
   28       //When
   29       app.Post("/",
   30         with =>
   31         {
   32           with.FormValue("url", "http://www.longurlplease.com/");
   33           with.HttpRequest();
   34         });
   35 
   36       //Then
   37       fakeStorage
   38         .Verify(store =>
   39                 store.SaveUrl("http://www.longurlplease.com/", 
   40                               It.IsAny<string>()));
   41     }
   42 
   43     [Fact]
   44     public void app_should_try_to_retrieve_url_when_getting_a_short_url()
   45     {
   46       //When
   47       app.Get("/shorturl",
   48         with => with.HttpRequest());
   49 
   50       //Then
   51       fakeStorage
   52         .Verify(store => 
   53                 store.GetUrlFor("shorturl"));
   54     }
   55   }
   56 }
   57 

A few interesting things go on in these tests.

Firstly, as stated above they specifify the interface UrlStore. They do so via the mock fakeStorage, and the calls to fakeStorage.Verify(...) which tells us that UrlStore should have two methods, SaveUrl and GetUrlFor.


Secondly we again use the Nancy.Testing.Browser type to call into the ShortUrl Nancy module. Remember that this goes though the whole Nancy pipeline, just like a real request from a browser. So we're genuinely testing the module from the outside. In the first test we do a HTTP POST, and in the second one we do a HTTP GET.


Thirdly in the constructor we're using another feature of Nancy.Testing; the ConfigurableBootstrapper. To understand this bit, a little detour is required. Nancy is very modular, everything in Nancy can be swapped for an alternative implementation via configuration. Furthermore Nancy apps uses IoC/DI from the get go. Out of the box Nancy uses TinyIOC, but that can (of course) be swapped with any other container - and NuGets exists for most (if not all) popular containers. The swapping out of things in Nancy apps is done through code, in a bootstrapper, which is a class in the app that implements INancyBootstrapper, and sets up the whole of Nancy and the app. To make this easy Nancy provides the DefaultNancyBootstrapper which can be used as the base class for app specific bootstrappers. Back to tests above. The ConfigurableBootstrapper, provides a simple way for tests to create specialized configurations through a fluent interface. The contructor in the code above registers the mock UrlStore as a dependincy, which means registering it in the TinyIOC container. In other words the parts of a the app that receives a UrlStore from the container will get the mock one when in the context of these tests.

But the UrlStore interface doesn't exists, so lets write it to make the tests compile:

    1 namespace ShortUrl
    2 {
    3   public interface UrlStore
    4   {
    5     void SaveUrl(string url, string shortenedUrl);
    6     string GetUrlFor(string shortenedUrl);
    7   }
    8 }

The tests don't run yet though, since our app does not use UrlStore at all. To make it do so, we change the application code to take a UrlStore in the module contructor, and use it for storage (particularly lines 7, 14 and 22):

    1 namespace ShortUrl
    2 {
    3   using Nancy;
    4 
    5   public class ShortUrlModule : NancyModule
    6   {
    7     public ShortUrlModule(UrlStore urlStore)
    8     {
    9       Get["/"] = _ => View["index.html"];
   10       Post["/"] = _ => ShortenUrl(urlStore);
   11       Get["/{shorturl}"] = param =>
   12       {
   13         string shortUrl = param.shorturl;
   14         return Response.AsRedirect(urlStore.GetUrlFor(shortUrl.ToString()));
   15       };
   16     }
   17 
   18     private Response ShortenUrl(UrlStore urlStore)
   19     {
   20       string longUrl = Request.Form.url;
   21       var shortUrl = ShortenUrl(longUrl);
   22       urlStore.SaveUrl(longUrl, shortUrl);
   23 
   24       return View["shortened_url", new { Request.Headers.Host, ShortUrl = shortUrl }];
   25     }
   26 
   27     private string ShortenUrl(string longUrl)
   28     {
   29       return "a" + longUrl.GetHashCode();
   30     }
   31   }
   32 }
   33 

And that makes the above tests run. But the end-to-end tests shown in part I don't run. The reason is they don't register a UrlStore with the container. They use the DefaultNancyBootstrapper, where no UrlStore is setup. To get past this we need to do a few things: Change the end-to-end tests to use an app specific bootstrapper, create an implementation of UrlStore that uses Mongo, and create an app specific bootstrapper. We'll start by driving out the Mongo implementation of UrlStore.

Shifting gears
To implement UrlStore against Mongo we need to shift TDD gears to using integration tests. The following tests, that drive the implementation of MongoUrlStore assume a Mongo server is running on localhost at port 27010:

    1 namespace ShortUrlTest
    2 {
    3   using System.Linq;
    4   using MongoDB.Bson;
    5   using MongoDB.Driver;
    6   using MongoDB.Driver.Builders;
    7   using ShortUrl.DataAccess;
    8   using Xunit;
    9 
   10   public class MongoUrlStoreTest
   11   {
   12     private string connectionString = "mongodb://localhost:27010/short_url_test";
   13     private MongoDatabase database;
   14     private MongoCollection<BsonDocument> urlCollection;
   15 
   16     public MongoUrlStoreTest()
   17     {
   18       //given
   19       database = MongoDatabase.Create(connectionString);
   20       urlCollection = database.GetCollection("urls");
   21         urlCollection.RemoveAll();
   22     }
   23 
   24     [Fact]
   25     public void should_store_urls_in_mongo()
   26     {
   27       //when
   28       var store = new MongoUrlStore(connectionString);
   29       store.SaveUrl("http://somelongurl.com/", "http://shorturl/abc");
   30 
   31       //then
   32       var urlFromDB = urlCollection
   33         .Find(Query.EQ("url", "http://somelongurl.com/"))
   34         .FirstOrDefault();
   35 
   36       Assert.NotNull(urlFromDB);
   37       Assert.Equal(urlFromDB["shortenedUrl"], "http://shorturl/abc");
   38     }
   39 
   40     [Fact]
   41     public void should_be_able_to_find_shortened_urls()
   42     {
   43       //given
   44       var store = new MongoUrlStore(connectionString);
   45       store.SaveUrl("http://somelongurl.com/", "http://shorturl/abc");
   46 
   47       //when
   48       var longUrl = store.GetUrlFor("http://shorturl/abc");
   49 
   50       //then
   51       Assert.Equal("http://somelongurl.com/", longUrl);
   52     }
   53   }
   54 }
   55 

These two test cases simply use the UrlStore interface, but also go directly to the Mongo instance to check that things are stored there. This is all quite straight forward, the one thing to notice though is that these test only assume that there is a Mongo server running, not that there is any particular database or collection present from the start. This is one of the ways Mongo is easy to work with, the databases and collections used in the code are just created for us behind the scenes. No friction.
To satisfy these tests we simply implement the UrlStore interface as follows:

    1 namespace ShortUrl.DataAccess
    2 {
    3   using System.Linq;
    4   using MongoDB.Bson;
    5   using MongoDB.Driver;
    6   using MongoDB.Driver.Builders;
    7 
    8   public class MongoUrlStore : UrlStore
    9   {
   10     private MongoDatabase database;
   11     private MongoCollection<BsonDocument> urls;
   12 
   13     public MongoUrlStore(string connectionString)
   14     {
   15       database = MongoDatabase.Create(connectionString);
   16       urls = database.GetCollection("urls");
   17     }
   18 
   19     public void SaveUrl(string url, string shortenedUrl)
   20     {
   21       urls.Insert(new {url, shortenedUrl});
   22     }
   23 
   24     public string GetUrlFor(string shortenedUrl)
   25     {
   26       var urlDocument =  
   27         urls
   28           .Find(Query.EQ("shortenedUrl", shortenedUrl))
   29           .FirstOrDefault();
   30 
   31       return 
   32         urlDocument == null ? 
   33         null : urlDocument["url"].AsString;
   34     }
   35   }
   36 }

The thing I really want to point out here is line 21. We just tell Mongo to store an anonymous object and the driver does the rest for us (i.e. serializes it to json). No O/R mapping code!
Now we have an interface for persisting things, our module uses that interface, and we have an implemtation of it against Mongo. The only thing remaining is wiring things up.

Shifting gears back the end-to-end tests
As mentioned earlier the end-to-end tests from part I don't run right now, to make them run we first change their setup to use an app specific bootstrapper:

   14    public BaseUrlSpec()
   15    {
   16      ShortUrlModule artificiaReference;
   17      app = new Browser(new Bootstrapper());
   18    }

We've changed line 17 to use Bootstrapper instead of DefaultNancyBootstrapper. The type Bootstrapper does not exists yet, so lets create it, and have it register MongoUrlStore with the container:

    1 namespace ShortUrl
    2 {
    3   using Nancy;
    4   using DataAccess;
    5 
    6   public class Bootstrapper : DefaultNancyBootstrapper
    7   {
    8     protected override void ConfigureApplicationContainer(TinyIoC.TinyIoCContainer container)
    9     {
   10       base.ConfigureApplicationContainer(container);
   11 
   12       var mongoUrlStore = new MongoUrlStore("mongodb://localhost:27010/short_url");
   13       container.Register<UrlStore>(mongoUrlStore);
   14     }
   15   }
   16 }

We use the DefaultNancyBootstrapper as a starting point, and just use one its hooks to do a little bit of app specific setup, namely registering MongoUrlStore. Using other overrides we could configure anything in Nancy. I really like that a lot.

Well that's it. All tests run again.

Updated code is a available on GitHub.

Sunday, October 16, 2011

Frictionless .NET Web App Development with Nancy Part II - Introducing a View Engine

In the last post I introduced a litte sample web app coded up with the Nancy web framework. The code presented in that post left a few things open for later enhancement. This post takes a stab one of those things: The part where a string.Format is used to create a bit of html, which is then just returned directly to the client, namely the POST action in this code:

 3   using System.Collections.Generic;
 4   using Nancy;
 5 
 6   public class ShortUrlModule : NancyModule
 7   {
 8         private static readonly Dictionary&amp;lt;string, string&amp;gt; urlMap = new Dictionary&amp;lt;string, string&amp;gt;();
 9 
10         public ShortUrlModule()
11         {
12             Get["/"] = _ =&amp;gt; View["index.html"];
13             Post["/"] = _ =&amp;gt; ShortenUrl();
14         }
15 
16         private string ShortenUrl()
17         {
18             string longUrl = Request.Form.url;
19             var shortUrl = ShortenUrl(longUrl);
20             urlMap[shortUrl] = longUrl;
21 
22             return ShortenedUrlView(shortUrl);
23         }
24 
25         private string ShortenUrl(string longUrl)
26         {
27             return "a" + longUrl.GetHashCode();
28         }
29 
30         private string ShortenedUrlView(string shortUrl)
31         {
32             return string.Format("<a id=\"shorturl\" href=\"http://{0}/{1}\">;http://{0}/{1}</a>", Request.Headers.Host, shortUrl);
33         }
34     }

Specifically the last method, 'ShortenedUrlView' is bad code: It's brittle, it doesn't produce valid HTML, and it's open for script injection. Therefore I want to separate that bit of view code from the module code: I want a view engine. Luckily Nancy supports a number of standard view engines(Razor, Spark, DotLiquid, NDjango) each of which are only a NuGet package away, but it also comes with its own appropriately named Super Simple View Engine, SSVE. For this sample SSVE will do, so let's just stick with that.

We add a file called shortened_url.sshtml to the Views folder and put this into it:

<html>
  <body>
    <a id="shorturl" href="http://@Model.Host/@Model.ShortUrl">
      http://@Model.Host/@Model.ShortUrl
    </a>
  </body>
</html>

As with Razor views the @ indicates code snippets. In the above we insert 'Host' and 'ShortUrl' properties from the view model in the view.

To use this we also need to modify the Nancy module code a bit. We need to return a View[] instead of simply a string:

   21         private Response ShortenUrl()
   22         {
   23             string longUrl = Request.Form.url;
   24             var shortUrl = ShortenUrl(longUrl);
   25             urlMap[shortUrl] = longUrl;
   26 
   27       return View["shortened_url", 
   28         new { Host = Request.Headers.Host, ShortUrl = shortUrl }];
   29         }
   30 
   31         private string ShortenUrl(string longUrl)
   32         {
   33             return "a" + longUrl.GetHashCode();
   34         }
   35 

We saw use of View[] last time, this time around we provide a model object along with the view name. This object is passed to the view code as the @Model.

That's it. Introduced a view engine. No friction.

The code for this sample is still available on GitHub. Now with the updates described here.

Monday, October 10, 2011

Frictionless .NET Web App Development with Nancy


This post is about a low ceremony approach to web apps in .NET. It's about just writting the app, without the framework getting in the way. It's about the same sort of feeling that Mogens Heller Grabe talks about with his notion of frictionless persistence with MongoDB. Only here it's about the web part.

I'll take you through a short and simple URL shortener sample app done with the Nancy web framework. A couple of more posts will probably follow on the subjects of view engines, persistence and hosting for this app. Also with an eye on low ceromony and frictionsless development.

What is Nancy? 
Nancy is a lightweight open source web framework in .NET. It has a declared goal of being the developers super-duper-happy-path. Nancy is lightweight in the sense that the number of concepts and the amount syntax you have to grok is minimal. That's why I like it, and that's why it provides the frictionless experience I'm after here.

First things first: The first red-green cycle
One of the first very nice things to notice about Nancy is that it supports TDD really well (much more so than ASP.NET MVC), so lets start looking at the sample by looking at the first test:

    9 public class BaseUrlSpec
   10 {
   11   [Fact]
   12   public void should_respond_ok()
   13   {
   14     var app = new Browser(new DefaultNancyBootstrapper());
   15     var response  = app.Get("/", with => with.HttpRequest());
   16     var statusCode = response.StatusCode;
   17     Assert.Equal(HttpStatusCode.OK, statusCode);
   18   }
   19 }

This is just an ice breaker test to get us going: It just tests that our app responds with an http 200 OK status code. There are nevertheless a couple of things to notice:
  1. Nancy.Testing provides us with the Browser class, which gives our tests an easy way to interact with the app as if they were a browser: The browser object allows for doing GET, PUT, POST and DELETE, PATCH and OPTIONS against the app, including setting up the body, the headers and the protocol. In the case of the above we're doing a GET over http to the relative URL "/", no body, no special headers.
  2. Nancy.Testing also provides a BrowserResponse type that allows for testing all sorts of things on the response from the app. The variable 'response' in the above has this type. Here we just check the status code, but in later examples we'll do a lot more.
There, that's the red part.

To make this run we only have to write this little snippet of Nancy based code:

    4   using Nancy;
    5 
    6   public class ShortUrlModule : NancyModule
    7   {
    8     public ShortUrlModule()
    9     {
   10       Get["/"] =_ => HttpStatusCode.OK;
   11     }
   12   }

Firstly this little piece of code shows the central concept of Nancy: It provides a DSL for responding to http requests. It does so by letting you specify what code should run on GET, PUT, POST, DELETE, PATCH and OPTIONS requests for different URIs. In the above we only specify one such action for one URI: GET for '/'. Secondly it shows another defining trait of Nancy: The framework really tries to make things easy for you, in this case illustrated by the fact we just return a 200 OK status code, but Nancy accepts that and turns it into a full response for us.

GETting the form
So returning a 200 OK does not make for much of an app. What we want here is a very simple URL shortener, so lets turn the front page of the app into a form with a field for the URL the user wants shortened and a submit button. Again we start with a test:

   28     [Fact]
   29     public void should_contain_a_form_with_an_input_field_for_a_url_and_a_button()
   30     {
   31       //when
   32       var baseUrlGetResponse = app.Get("/", with => with.HttpRequest());
   33 
   34       //then
   35       baseUrlGetResponse.Body["form"]
   36         .ShouldExist();
   37 
   38       baseUrlGetResponse.Body["input#url"]
   39         .ShouldExistOnce();
   40 
   41       baseUrlGetResponse.Body["label"]
   42         .ShouldExistOnce().And
   43         .ShouldContain("Url: ");
   44 
   45       baseUrlGetResponse.Body["input#submit"]
   46         .ShouldExistOnce();
   47     }

Here we see some more of Nancys test emphasis: The BrowseResponse type mentioned above provides a Body property that lets our tests search through the body of the response using CSS selectors and make assertions on the results using a set of fluent 'Should' style extensions. For instance the above asserts that there is exactly one input tag with the id 'url' and that there is one label tag which furthermore contains the text 'Url: '. This, I must sat, is just awesome, and is a very good level to test at: Just below the pixels of the UI, and just above the real http stack of the real web server.

To make this run we need only do slightly more than in the previous cycle: We alter the application code to this:

 4   using Nancy;
 5 
 6   public class ShortUrlModule : NancyModule
 7   {
 8         public ShortUrlModule()
 9         {
10           Get["/"] = _ => View["index.html"];
11         }
12   }

and add the following index.html file to a Views folder:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <html>
     <body>
       <form method="post">
       <label>Url: </label>
      <input type="text" name="url" id="url"/>
      <input type="submit" value="shorten" id="submit"/>
    </form>
  </body>
</html>

Now we see Nancy trying to make things easy again: Just indicate in the application code that you want to return a view by saying View["index.html"], and Nancy looks in your views folders, finds the view and off we go.

POSTing the form
Next step is reacting to a POST of the form we just made, by shortening the URL. Let's set up a test for that:

 49     [Fact]
 50     public void should_return_shortened_url_when_posting_url()
 51     {
 52       //when
 53       var baseUrlPostResponse = app.Post("/",
 54         with =>
 55         {
 56           with.FormValue("url", "http://http://www.longurlplease.com/");
 57           with.HttpRequest();
 58         });
 59 
 60       baseUrlPostResponse.Body["a#shorturl"]
 61         .ShouldExist().And
 62         .ShouldContain("http://");
 63     }

Here we see how the app object is used for sending a POST to the app, and along with it the appropriate form values; in this case just the url. This starts to show the flexibility and ease of use of the Browser type.

Considering how we've handled the GET request until now, handling the POST is as straightforward:

 3   using System.Collections.Generic;
 4   using Nancy;
 5 
 6   public class ShortUrlModule : NancyModule
 7   {
 8         private static readonly Dictionary<string, string> urlMap = new Dictionary<string, string>();
 9 
10         public ShortUrlModule()
11         {
12             Get["/"] = _ => View["index.html"];
13             Post["/"] = _ => ShortenUrl();
14         }
15 
16         private string ShortenUrl()
17         {
18             string longUrl = Request.Form.url;
19             var shortUrl = ShortenUrl(longUrl);
20             urlMap[shortUrl] = longUrl;
21 
22             return ShortenedUrlView(shortUrl);
23         }
24 
25         private string ShortenUrl(string longUrl)
26         {
27             return "a" + longUrl.GetHashCode();
28         }
29 
30         private string ShortenedUrlView(string shortUrl)
31         {
32             return string.Format("<a id=\"shorturl\" href=\"http://{0}/{1}\">http://{0}/{1}</a>", Request.Headers.Host, shortUrl);
33         }
34     }

This is all pretty straight forward. The Nancy parts of this are:
  1. The use of POST...which does just what you expect.
  2. The return of a string in the last method. That bubles all the way up, and becomes the repsonse back to Nancy. Again Nancy is nice to us, sets the content type to text/html and the status code to 200 OK. This is not the nicest code on my part, so I might just return to refactor it in a future post.
The above of course is not very clever about the shortening, and does not exactly persist the short URLs in a good permanent place. I'll return to the persistence in a furture post.

Redirect
Only one part is missing for a simplistic but functioning URL shortener: The app must redirect the shortened URLs to the original longer one.
Again lets start with the test:

 65     [Fact]
 66     public void should_redirect_to_original_url_when_getting_short_url()
 67     {
 68       //when
 69       var baseUrlPostResponse = app.Post("/",
 70         with =>
 71         {
 72           with.FormValue("url", "http://www.longurlplease.com/");
 73           with.HttpRequest();
 74         }).GetBodyAsXml();
 75 
 76       var shortUrl = baseUrlPostResponse
 77         .Element("a")
 78         .Attribute("href").Value
 79         .Split('/')
 80         .Last();
 81 
 82       //then
 83       app.Get("/" + shortUrl, with => with.HttpRequest())
 84         .ShouldHaveRedirectedTo("http://www.longurlplease.com/");
 85     }

We do the POST again, find the short URL with a bit of LINQ-to-xml and then do a GET to that. And then just assert that the redirect happened. Pretty straight forward except maybe for the Linq-to-xml part.

To make the last test run we add this to our application code:

 14  Get["/{shorturl}"] = param =>
 15  {
 16     string shortUrl = param.shorturl;
 17     return Response.AsRedirect(urlMap[shortUrl.ToString()]);
 18  };


which is an action for a whole set of URIs, namely the URIs matching the URI template "/{shorturl}". In the action we access the 'shorturl' part of the URI through the param.shorturl; all parts of the templatized URI will be availbe like that through the dynamic param. Nice.

That's it. We have a simplistic URL shortener. No friction.

The source is availble on github, and more Nancy information is avaible on the Nancy web site.