Monday, July 14, 2008

A few less strings in MonoRail


In the same spirit as my previous post, I wrote a couple of extensions methods to avoid strings when redirecting in Castle MonoRail.
Let's say you have this controller:
public class HomeController : SmartDispatcherController
{
public void Index()
{
}

public void SaveInformation(String name, int age, DateTime dob)
{
// work work work

// Send the user back to the index
RedirectToAction("index");
}
}

Now you can write the redirect like this:

this.RedirectToAction(c => c.Index());

It also works with parameters, i.e. if you have an action like this:

public void Index(int a) {}

you can do:

this.RedirectToAction(c => Index(1));

and it will redirect to /home/index.castle?a=1 (or whatever extension you're using)

It even works with objects and [DataBind] (with some limitations, see below):

public class Properties {
public int SomeValue { get; set; }
}

public class SmartTest2Controller : SmartDispatcherController {
public void DataBinding([DataBind("prefi")] Properties prop) {}
public void Index() {
this.RedirectToAction(c => c.DataBinding(new Properties {SomeValue = 22}));
}
}

Which will redirect to /SmartTest2/DataBinding.castle?prefi.SomeValue=22

There's also support for [ARDataBind] and [ARFetch]:

    public class ARController : ARSmartDispatcherController {
public void Index() {
this.RedirectToAction(c => c.ARFetchAction(new Entity { PK = 5, Name = "Robert Duvall" }));
this.RedirectToAction(c => c.ARAction(new Entity { PK = 4, Name = "John Q" }));
}
public void ARAction([ARDataBind("pre")] Entity e) {}
public void ARFetchAction([ARFetch("pre")] Entity e) { }
}

Which would respectively redirect to /AR/ARFetchAction.castle?pre=5 and /AR/ARAction.castle?pre.PK=4&pre.Name=John+Q
(I was watching John Q while writing this :-) )

ActiveRecord support is implemented in another assembly, to cleanly separate the dependencies. When using the ActiveRecord extensions, you have to initialize it in your Application_Start():

Setup.ForAll(new DefaultExtensionsProvider {ExtUtils = new ARUtils()});
This instructs the extension methods to use the ActiveRecord helpers.

Code is here, let me know your opinion...

Caveats / limitations (for now):
  • Doesn't work with nested object databinding
  • Doesn't work with arrays of objects
  • Works on Castle RC3. Trunk has been refactored a lot regarding controllers since RC3, so this code would have to be adapted (extending IRedirectSupport instead of Controller and such)

UPDATE 5/16/2009: I just found out there already was a similar project on castle contrib.