A Simple IronPython ControllerFactory for ASP.NET MVC

The default behavior for ASP.NET MVC is to wire up a controller instance to the controller value found in a request's RouteData. This mapping is desirable for its simplicity, but limited in its ability to provide an extensible configuration model. Managing properties on controllers would likely require either a custom configuration section or extensive use of AppSettings.

An alternative approach would be to use an IoC container, such as Spring.NET. This approach simply manages controller instances as standard Spring container objects. An MVC contrib project already provides support for a Spring Controller factory (among others). This article will present an alternative approach in which controller instances are configured in an IronPython script that lives alongside the MVC application.

The PyControllerFactory will make use of three private static objects to manage controller creation. The _controllers dictionary is used to store the controller configuration functions (see below) and a static instance of the DLR's ScriptRuntime is maintained to handle all incoming requests.

The real work is done in a static constructor that will execute the Python script. The executing assembly is passed into the runtime, with the assumption that the controllers will be found in this assembly. A more complete example would clearly allow for a list of assembly references to be included. Next, the Python file is executed.

Unlike previous CodeVoyeur articles that use IronPython as an external configuration language, this sample does not use XML to organize data. Instead, each controller name is mapped to a function name. The return value of each function is a configured instance of a controller.

The CreateController implementation is then very straight forward. This factory method takes advantage of the fact that a function is just another piece of data in a Python script. First, the _controllers Dictionary is checked to see if an object's prototype function has already been called (it would be stored if so). If not, the _runtime's Globals collection is interrogated. The name of the controller should match the name of a function. The function reference is then stored in the _controllers dictionary. Next, the Call method of _runtime's Operations property is called. This call simply invokes the Python function, returning a fully constructed Controller instance.