3

How can I write custom model binder for complex model with collection of polymorphic objects?

I have the next structure of models:

public class CustomAttributeValueViewModel
{
    public int? CustomAttributeValueId { get; set; }
    public int CustomAttributeId { get; set; }
    public int EntityId { get; set; }
    public CustomisableTypes EntityType { get; set; }
    public string AttributeClassType { get; set; }
}

public class CustomStringViewModel : CustomAttributeValueViewModel
{
    public string Value { get; set; }
}

public class CustomIntegerViewModel : CustomAttributeValueViewModel
{
    public int Value { get; set; }
}

And if I want to bind CustomAttributeValueViewModel to some of it's inheritors, I use such custom model binder:

public class CustomAttributeValueModelBinder : DefaultModelBinder
{
    protected override object CreateModel(
        ControllerContext controllerContext,
        ModelBindingContext bindingContext,
        Type modelType)
    {
        if (modelType == typeof(CustomAttributeValueViewModel))
        {
            var attributeClassType = (string)bindingContext.ValueProvider
                .GetValue("AttributeClassType")
                .ConvertTo(typeof(string));

            Assembly assembly = typeof(CustomAttributeValueViewModel).Assembly;
            Type instantiationType = assembly.GetType(attributeClassType, true);

            var obj = Activator.CreateInstance(instantiationType);
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, instantiationType);
            bindingContext.ModelMetadata.Model = obj;
            return obj;
        }

        return base.CreateModel(controllerContext, bindingContext, modelType);
    }
}

It works great. But now I want to bind such models as items of collection of another model. For instance:

public class SomeEntity
{
    // different properties here

    public IList<CustomAttributeValueViewModel> CustomAttributes { get; set; }
}

How can I do that?

EDITED:

I want to bind a posted data which I received from a client. For more clarity it is an example of my POST HTTP request:

POST someUrl HTTP/1.1
User-Agent: Fiddler
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 115

{
  "ProductName": "Product Name",
  "CustomAttributeValues": [
    {
      "CustomAttributeId": "1",
      "Value": "123",
      "AttributeClassType": "namespace.CustomStringViewModel"
    }
  ]
}

And I receive this data in my action:

public void Save([ModelBinder(typeof(SomeBinder))] SomeEntity model)
{
    // some logic
}

I want to write such binder for getting collection of inheritors.

5
  • Doesn't new SomeEntity().CustomAttributes.Add(myModel); work? Commented Nov 3, 2014 at 7:49
  • @AndreiV, I think you didn't understand what I meant. I want to bind SomeEntity in my action. Commented Nov 3, 2014 at 7:53
  • No, I don't. Can you please clarify? Commented Nov 3, 2014 at 7:54
  • Can you show your View for SomeEntity model? Commented Nov 3, 2014 at 7:57
  • @MaxBrodin, I have written more details in my question. Commented Nov 3, 2014 at 8:11

1 Answer 1

4

You need to include full path to the AttributeClassType,

var valueProviderResult = bindingContext.ValueProvider
                            .GetValue(bindingContext.ModelName + ".AttributeClassType");

please take a look at this working Github sample

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.