Monday, January 2, 2012

Customizing an ASP.NET MVC app with a dynamic language

Overview
I like to configure and extend application or service written in C# by using a dynamic language. This form of architecture allows to create customizable application, and the customization is simple, immediate and clean.

Goal
In this post I am going to show how to build customizable ASP.NET MVC application and the nice syntax obtained.

This is just a prototype to showcase my idea.

In my project I created a folder Dictionary, which contains Python and PowerShell files. For now we will focus on the Python files.


The file App.py contains one Python dictionary with 2 entries. As you may reconized this file is also JSON compatible and even if you do not know Python, it is easy to read and understand.
Dic = {

    "ApplicationTitle"   : "My Customized App Title",
    "ApplicationVersion" : 1.2
}
In my view, I reference the entries this way.

AppTitle:@ViewBag.ApplicationTitle AppVersion:@ViewBag.ApplicationVersion

In my C# controler the only change is the base class.
public class HomeController : Dynamic4MVC.ControllerExtended {

}
So far the App.py file is just a static configuration file.

I added a new entrie named SupportedDays. This entry is a list of string and it is initialized by invoking the function GetSupportedDays(). Now that's where using a dynamic language versus an XML file becomes interesting, because we can execute code to initialize data, when the Python file is loaded.
def GetSupportedDays():
    return ["Monday", "Wednesday", "Friday"]

Dic = {

    "ApplicationTitle"   : "My Customized App Title",
    "ApplicationVersion" : 1.2,
    "SupportedDays"      : GetSupportedDays()    
}
In my view, I reference the entry SupportedDays this way.
SupportedDays:
    @foreach (var d in ViewBag.SupportedDays) {
        @: @d,
    }
We can go a little bit further, by implementing our own class, instantiating objects and invoke methods. The method ToString() will be automatically invoked by the Razor engine.
class User(object):

    def __init__(self, userName):
        self.UserName = userName

    def ToString(self):
        return "user:%s" % self.UserName

Dic = {
    "Users" : [ 
           User("FTorres"), 
           User("RDescartes")
    ]
}
In my view, I reference the entry Users this way.
@foreach (var u in ViewBag.Users) {
        @: User:@u
}   
Conclusion
At this point we can build a nice DSL (Martin Fowler called them Internal DSL) dedicated to the customization of the application.

Python syntax is clean and succinct, and IronPython being a .NET language, there is no integration problem and it is fast. Mixing C# 4.0 and IronPython, is easy and very powerful. It is possible to do it with .NET C# 2.0/3.5 with a little bit more difficulties.

JavaScript is also a possibilty with the Jurassic runtime which is slow compared to the JavaScript runtime in Chrome or IE9, though speed is not really a problem here.

Mixing C# and PowerShell v 2 is easy, but the API is kind of ugly and cannot leverage the dynamic feature of C# 4.0 out of the box, like with IronPython. I had to write some internal wrapper described in my post Running PowerShell from C# with a hint of dynamic. With PowerShell v 3, the problem should be solved.

Depending of your type of application, you may have to cache the dictionary in the Session object, the Application object or your mem cache, because loading and evaluating IronPython or PowerShell code is slow.

Obviously, those who hate dynamic languages will find this post awful. A more valid question is to ask is: Is it reasonable to ship on a product machine code in a text file?

To this question I generally find more Pros than Cons. That's just me.

The source code is on github at DynamicCsToPowerShell-Library

2 comments:

  1. Very interesting post Fred. What else is in your base controller? Care to share the code?

    ReplyDelete
  2. The source code is on github
    https://github.com/fredericaltorres/DynamicCsToPowerShell-Library

    ReplyDelete