Question

I have the interface IInterface and the class Concrete which implements it

I have a view

@model IEnumerable<IInterface>
@for (int i = 0; i < Model.Count(); i++)
{
    @Html.EditorFor(x => x[i])
}
<span id="result"></span>

an editor template Concrete.cshtml

@model Concrete
@Ajax.BeginForm("Action", new AjaxOptions { UpdateTargetId = "result" })
{
    @Html.Hidden("ModelType", Model.GetType())
    <input type="submit" />
}

with action:

public string Action(IInterface interface) { return "success"; }

and a model binder:

public class MyModelBinder : DefaultModelBinder
{
    protected override CreateModel(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext, 
        Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue(
                            bindingContext.ModelName + ".ModelType"
                        );

        ...

I've used this before with the IInterface within a ViewModel and it worked fine, however, now when I submit my Ajax form bindingContext.ModelName is empty.

Examining ValueProvider in debugger I can see that it contains a FormValueProvider who's _values contains the key [0].Interface.ModelType.

Using the Immediate Window I can confirm calling .GetValue("[0].Interface.ModelType") returns the appropriate typeValue.

How can I either get bindingContext.ModelName to not be empty or how can I get the string "[0].Interface.ModelType" I need?

Was it helpful?

Solution

Okay I found a hacky solution which is by no means satisfactory:

var typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType");

if (typeValue == null)
{
    var enumerable = (IEnumerable)bindingContext.ValueProvider;

    var formValueProvider = enumerable.OfType<FormValueProvider>().Single();

    var field = typeof(NameValueCollectionValueProvider).GetField(
                    "_values", 
                    BindingFlags.NonPublic | BindingFlags.Instance
                );

    var dictionary = (IDictionary)field.GetValue(formValueProvider);

    var keys = (IEnumerable<string>)dictionary.Keys;

    var key = keys.FirstOrDefault(x => x.EndsWith(".ModelType"));

    typeValue = bindingContext.ValueProvider.GetValue(key);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top