javascript – How to use inheritance and polymorphism when passing a JSON to a C# MVC Controller?

Question:

I have an MVC method that takes a client class as a parameter:

      public async Task<ActionResult> Cadastrar(cliente model)
      {
      }

It turns out that this class has two children, a class called person. and another class called company which also inherits from customer.

I wonder if it's possible (and how) I do to pass a generic JSON to this method? it can be either a PERSON object or a COMPANY object. A polymorphism indeed.

I've already tried to pass an object to a person or company and it didn't work. but if I put a person or company in the place of a client and pass the JSON I normally receive the data.

Answer:

Basically, using a Model Binder written by you and a little 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 the Application_Start event of your Global.asax.cs , register your Model Binder :

protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(Cliente), new ClienteModelBinder());
}

In the form or in JSON, you'll need to pass a Tipo field so the Model Binder knows what's being passed:

@Html.Hidden("Tipo", Model.GetType())

Or:

{ 'Tipo': 'Pessoa' }

Or, you can try something else. For example, if the value passed has defined a CPF or CNPJ, or even a name or corporate name, then you don't need a Tipo field in the form or in the 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;
}
Scroll to Top