Search code examples
c#asp.net-mvcasp.net-mvc-4model-bindingproxy-classes

Implementing a custom model binder in MVC to resolve types from container


In a nutshell, my question boils down to this:

I need to implement a custom model binder in MVC4 that resolves models from container/service locator, whatever. I have implemented the following model binder:

public class ServiceLocatorModelBinder : DefaultModelBinder
{
    private readonly IServiceLocator _serviceLocator;

    public ServiceLocatorModelBinder(IServiceLocator serviceLocator)
    {
        _serviceLocator = serviceLocator;
    }

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType");
        var type = Type.GetType(
            (string)typeValue.ConvertTo(typeof(string)),
            true
        );
        var model = _serviceLocator.GetInstance(modelType);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
        return model;
    }
}

And now I would like to use this in place of the DefaultModelBinder in mvc to resolve all my models. How do I do this?

To clarify my need for doing this at all (as in general it's considered best practice to just use concrete simple classes for view models/models), is that I'm experimenting with the concept of automatically generating proxies in place of my simple view model/poco classes throughout my application, and as such I don't have a concrete type to bind to. The goal I'm hoping to achieve is taking the pattern of keeping models/view models simple, and enforcing it one step further by making it impossible for anyone to add any logic at all to these classes. This is where I need a container to resolve model types.


Solution

  • How do I do this?

    You could replace the default model binder with your custom one in Application_Start:

    IServiceLocator sl = ...
    ModelBinders.Binders.DefaultBinder = new ServiceLocatorModelBinder(sl);