Click here to Skip to main content
15,881,173 members
Articles / Web Development / ASP.NET / ASP.NET2.0
Tip/Trick

How to Bind Derived Type in MVC View

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
9 May 2013CPOL2 min read 19.9K   2   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:

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

And the other derived classes as below…

C#
[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:

ASP.NET
<% 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.

C#
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.

ASP.NET
<%= 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.

C#
// 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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Accenture
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
NigeE30-Aug-13 2:44
NigeE30-Aug-13 2:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.