tags:

views:

949

answers:

2

You'll notice that Preview 5 includes the following in their release notes:

Added support for custom model binders. Custom binders allow you to define complex types as parameters to an action method. To use this feature, mark the complex type or the parameter declaration with [ModelBinder(…)].

So how do you go about actually using this facility so that I can have something like this work in my Controller:

public ActionResult Insert(Contact contact)
{
    if (this.ViewData.ModelState.IsValid)
    {
        this.contactService.SaveContact(contact);

        return this.RedirectToAction("Details", new { id = contact.ID}
    }
}
+2  A: 

Well I looked into this. ASP.NET provides a common location for registering the implementation of IControlBinders. They also have the basics of this working via the new Controller.UpdateModel method.

So I essentially combined these two concepts by creating an implementation of IModelBinder that does the same thing as Controller.UpdateModel for all public properties of the modelClass.

public class ModelBinder : IModelBinder 
{
    public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState)
    {
        object model = Activator.CreateInstance(modelType);

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(model);
        foreach (PropertyDescriptor descriptor in properties)
        {
            string key = modelName + "." + descriptor.Name;
            object value = ModelBinders.GetBinder(descriptor.PropertyType).GetValue(controllerContext, key, descriptor.PropertyType, modelState);
            if (value != null)
            {
                try
                {
                    descriptor.SetValue(model, value);
                    continue;
                }
                catch
                {
                    string errorMessage = String.Format("The value '{0}' is invalid for property '{1}'.", value, key);
                    string attemptedValue = Convert.ToString(value);
                    modelState.AddModelError(key, attemptedValue, errorMessage);
                }
            }
        }

        return model;
    }
}

In your Global.asax.cs you'd need to add something like this:

    protected void Application_Start()
    {
        ModelBinders.Binders.Add(typeof(Contact), new ModelBinder());
Joseph Kingry