Basically, using a Model Binder written by you and a bit of Reflection:
public class ClienteModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var tipoString = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Tipo");
var tipo = Type.GetType(
(string)tipoString.ConvertTo(typeof(string)),
true
);
var model = Activator.CreateInstance(type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, tipo);
return model;
}
}
In event Application_Start
of your Global.asax.cs
, register your Model Binder :
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(Cliente), new ClienteModelBinder());
}
In form
or in JSON, you need to pass a Tipo
field so that Model Binder knows what is being passed:
@Html.Hidden("Tipo", Model.GetType())
Or:
{ 'Tipo': 'Pessoa' }
Or, you can test something else. For example, if the passed value has defined a CPF or CNPJ, or a name or business name, it does not need a Tipo
field in form
or JSON:
var cpf = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Cpf");
if (cpf != null)
{
/* É Pessoa Física */
var model = Activator.CreateInstance(typeof(Pessoa));
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(Pessoa));
return model;
}