[Update: Simone brought my attention to the fact that ComplexModelBinder which comes with the framework does exactly that.  You can find more info here]

ASP.NET MVC Preview 5 introduce the ModelBinder attribute that can be used to decorate a complex type in an Action.  This allows us to have actions that look like this

public ActionResult Create([ModelBinder(typeof(GenericBinder))] ContactList myList)

 

Instead of this:

public ActionResult Create(string name, string description)

 

The problem is that you have to build a Binder for every complex type you want to use as a parameter.  For example, Maarten Balliauw created a model binder on his blog and it looks like this:

public class ContactBinder : IModelBinder
{
    #region IModelBinder Members
    public object GetValue(ControllerContext controllerContext,
                 string modelName, Type modelType,
                 ModelStateDictionary modelState)
    {
        if (modelType == typeof(Contact))
        {
            return new Contact
            {
                Name = controllerContext.HttpContext.Request.Form["name"] ?? "",
                Email = controllerContext.HttpContext.Request.Form["email"] ?? "",
                Message = controllerContext.HttpContext.Request.Form["message"] ?? ""
            };
        }
        return null;
    }
    #endregion
}

 

Now that is a lot of typing and because I am lazy, I decided to create a generic binder that uses reflection and can work with all my complex types. 

Note: By generic I mean common – it has nothing to do with .net Generics

Also note that this will only work if you follow these conventions:

  1. The html field name must match the property name
  2. User lower case names for the html fields
  3. You don’t have to user lower case on your model properties

Here is the very rough and untested Generic Binder:

class GenericBinder : IModelBinder
{
    public object GetValue(ControllerContext controllerContext,
                            string modelName, Type modelType,
                            ModelStateDictionary modelState)
    {
        var instance = Activator.CreateInstance(modelType);
        foreach (var prop in modelType.GetProperties())
        {
            prop.SetValue(instance,
                    controllerContext.HttpContext.Request
                                    .Form[prop.Name.ToLower()],
                    null);
        }
        return instance;
    }
}

 

If you find any bugs or have a better implementation, please share.

This entry was posted on Wednesday, September 3rd, 2008 at 1:53 pm and is filed under ASP.NET MVC. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.