Lightweight Development in .Net: Nancy

Tags: web-development, dot-net, lightweight-dot-net, nancy-fx

While .Net environment is a powerful application development framework, there is one significant downside. As a result of its enterprise background, most of the things are heavyweight for simple development tasks or prototyping, the area in which some other platforms excel. Luckily, in the past year or so, things have started changing - it's time to meet Nancy.

Even with the rise of the ASP.Net MVC framework, which made things a lot different in the .Net world, this ecosystem still needs some less enterprisey and more opinionated approach to simpler scenarios, matching today's agile practices better. That's the area where Ruby on Rails platform has a significant head-start with great defaults configured out of the box (and easily interchangeable if needed).

But even in the Ruby community, the Rails became the solution that seemed too heavy for some simpler use cases (micro-sites and prototyping). As a result, Sinatra framework came out, targeting those.

That situation was calling to reconsider what .Net ecosystem has to offer in this space. As you expect, the answer was - nothing really (unless you want to do spaghetti-like ASP.Net pages code and markup mix, like we did in the classic ASP and PHP era - which you don't).

Luckily in the end of 2010 (Sinatra was introduced at the RubyConf 2008), the first announcement of Nancy, a Sinatra inspired framework for .Net, came out by Andreas Håkansson (aka @TheCodeJunkie). Instead of switching over to Ruby, it enables us to keep working with C#, the language we know, while getting the flexibility and speed we have never imagined possible before.

Real world implementation

While I had peeked into Nancy several times, I've finally managed to find some time and push a real implementation on top of it.

The perfect candidate for such experiment was Muzika.hr FanClub microsite, the part of the portal not integrated within the main CMS. While I've made the data access component migration from ADO.Net to Massive recently, the application still kept the 'ASP.Net Web Site' model with old controls-based paradigm and code-behind mixed with layout in .aspx pages.

The goal that I've had for some time was to separate the server-side code from the markup, to make design changes easier. But, as it's a total of a 5-page microsite, setting it up as the fully-blown ASP.Net MVC application seemed just inappropriate. Therefore, using Nancy to do it popped up as a reasonable option.

The result was a very pleasant experience, and the job done really quickly.

Code samples

Instead of just talk, let's see some code. It's based on .Net 4, with Massive as Data Access component using dynamics for the data model and Spark View Engine for layout (there are other options available). Dynamics allowed for no explicit model classes which helped in having less code in the end.

The following code examples are simplified a bit for better understanding when reading this blog post. The complete Nancy module listing can be found at https://gist.github.com/c2d91372d6c7a752cda2

The way Nancy works is that everything is a module, with actions URLs specified within. So the skeleton is:

using Nancy;
public class FanClubModule : NancyModule
{
public FanClubModule()
{
// actions URLs mappings and methods here
}
}

First thing referenced within the constructor will be static assets routes - JS, CSS and images. Notice the separate response methods for each of them (more exist, like AsJson(), AsXml(), AsRedirect()), Nancy will take care of the correct response MIME type:

public FanClubModule()
{
Get[@"/js/{name}"] = x => {
return Response.AsJs(string.Format("js/{0}", (string)x.name));
};

Get[@"/css/{name}"] = x => {
return Response.AsCss(string.Format("css/{0}", (string)x.name));
};

Get[@"/img/{name}"] = x => {
return Response.AsImage(string.Format("img/{0}", (string)x.name));
};

// ...actions follow here
}

The rest of the code represents routes for actions, just like controllers' actions in the MVC model. Routes are defined when defining the action itself, so no separate code file containing all the routes (notice the curly braces which define the parameter, whereas no braces make the literal string in the URL; documentation contains more details):

public FanClubModule()
{
// ...actions follow here

Get["/{name}"] = x => {
string view = (string)x.name;

var articles = Repository.GetFanClubArticles();
var offers = Repository.GetActiveOffers();

var categorizedOffers = new Dictionary<dynamic, dynamic>();
offers.ToList().ForEach(o => {
if (!categorizedOffers.ContainsKey(o.categoryName.ToString()))
{
categorizedOffers.Add(o.categoryName, new List<dynamic>());
}
categorizedOffers[o.categoryName].Add(o);
});

dynamic model = new {
Articles = articles,
CategorizedOffers = categorizedOffers,
};
return View[view, model];
};

// ...more actions follow...
}

You might have noticed calling some static methods on the Repository class. That's encapsulation of Massive code for fetching data from the database, which is the other part of a lightweight development magic I will cover in a separate post...

Processing form POST requests is pretty similar, here is the short overview:

public FanClubModule()
{
// ...more actions follow...

Post["/rezervacija"] = x => {
string senderName = Request.Form.name.Value.Trim();
string senderAddress = Request.Form.email.Value.Trim();
// ...after getting the parameters from request, do the processing
return Response.AsRedirect(SUCCESS_URL); // PRG pattern applied
};
}

Final thoughts on Nancy

The complete experience with Nancy was really sweet. I've had some really minor friction points, mostly related to getting my head around how Nancy serves static assets. Shortly - keep static files in a subdirectory (common or separate for each type of asset), and then provide routes to them.

Besides that, Nancy is extremely simple and pleasant to work with. You get your routing set up easily, get the out-of-the-box code and layout separation experience, and most of all you can have everything running without messing up with configuration, at least for Nancy (you will have to configure the data access component though, and the view engine if it needs to be configured).

If you manage to find some spare time, take Nancy for the test-run - you will like it. Whether you have to make some micro-site or to propose some future application prototype, Nancy is a perfect fit. You may even end up surprised how far Nancy can take you.

These micro- and lightweight frameworks are like a breath of fresh air in the web application development, removing the unnecessary overhead but still keeping the concerns separated. Which is actually pretty awesome!

Story comments:

blog comments powered by Disqus