Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to Bind Derived Type in MVC View

0.00/5 (No votes)
10 May 2013 1  
How to bind Derived Type in MVC View

Introduction

Normally when we bind the Derived type (or derived type collection) to the MVC View, it always return the actual base type on controller, because our Model (business or domain entity) always has the BaseType. To persist the derived type (during postbacks), we have to create our own custom binder that actually maintain its derived type.

This tip contains a solution of persisting Derived Types binded to base type object in MVC view.

Background

I have faced a problem in my project. I have an array of base class objects, whose individual items refer to derived class objects. I need to bind this array in my MVC view, but in Model binding approach it loses the actual derived type on post back. So to resolve this problem, I have created a customized DerivedTypeModelBinder, with the help of which I am able to persist derived types binded to base class objects.

Using the Code

I have base class WarrantyBase as below:

[DataContract]
[Serializable]
[XmlInclude(typeof(AWarranty))]
[XmlInclude(typeof(BWarranty))]
[KnownType(typeof(AWarranty))]
[KnownType(typeof(BWarranty))]
public class WarrantyBase
{
}

And the other derived classes as below…

[DataContract]
[Serializable]
public class AWarranty : WarrantyBase
{

}
[DataContract]
[Serializable]
public class BWarranty: WarrantyBase
{

}

Then I have an array of Base class that I need to bind on my view as:

<% for (int i = 0; i < Model.Warranties.Count; i++)
{ %>
<tr>
<td>
<%= this.CheckBox(c => c.Warranties[i].IsSelected)%>
</td>
</tr>

When I am getting my model in Postback, I always get the base class objects and not able to convert those base objects to derived. So, I need a solution by which my view always return the actual derived type and not the base ones. So to achieve this, I have to write a DerivedTypeModelBinder which is derived from DefaultModelBinder, as shown in the below code snippet.

public class DerivedTypeModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, 
ModelBindingContext bindingContext, Type modelType)
{
return base.CreateModel(controllerContext, bindingContext, 
GetModelType(controllerContext, bindingContext, modelType));
}
protected override ICustomTypeDescriptor GetTypeDescriptor
(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var modelType = GetModelType(controllerContext, bindingContext, bindingContext.ModelType);
return new AssociatedMetadataTypeTypeDescriptionProvider(modelType).GetTypeDescriptor(modelType);
}
private static Type GetModelType(ControllerContext controllerContext, 
ModelBindingContext bindingContext, Type modelType)
{
if (bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName + ".BindingType"))
{
modelType = System.Type.GetType(((string[])bindingContext.ValueProvider.GetValue
(bindingContext.ModelName + ".BindingType").RawValue)[0]);
}
return modelType;
}
}

And then, you have to take a hidden control to bind the actual type in Views to persist the same during postbacks.

<%= Html.Hidden(string.Format("Warranties[{0}].BindingType", i), 
Model.Warranties[i].GetType().AssemblyQualifiedName)%>

Then the last step is to register your customized binder in Global.asax file in RegisterArea or RegisterRoute method.

// Register the binder in below place…
public override void RegisterArea(AreaRegistrationContext context)
{
RegisterAreaEmbeddedResources();
ModelBinders.Binders.Add(typeof(WarrantyBase), new Common.Helpers.DerivedTypeModelBinder());
} 

Conclusion

This solution solves the problem of binding base class object in view and getting actual derived class objects in postback.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here