How to inject IRepository<T> in a custom ModelBinder

Topics: General
Apr 19, 2013 at 10:48 AM
Edited Apr 19, 2013 at 10:49 AM
Hello,
We are trying to use custom model binders for our modules. The idea is to move the data access logic from the action methods to custom model binders.

The problem is that we can't figure out how to inject IRepository<T> or any other "IDependency" in our model binders. Here is the code we have.

This is our action method in the controller:
public ActionResult EditPersonalInfo( Profile profile )
{
    return this.View(profile);
}
This is the custom model binder:
public class ProfileModelBinder : IModelBinder
{
    private IRepository<Profile> profileRepository;

    public ProfileModelBinder( IRepository<Profile> profileRepository )
    {
        this.profileRepository = profileRepository;    
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        int id = ( int )controllerContext.RouteData.Values["Id"];
        Profile profile = profileRepository.Get( id );
        // Other code
        return profile;
    }
}
And we are registering the custom model binder in an autofac module:
public class MyModule : Module
{
    protected override void Load( ContainerBuilder builder )
    {
        // How to inject IRepository<Profile> here ???
        ModelBinders.Binders.Add( typeof( Profile ), new ProfileModelBinder( null ) );
        // Other type registration
        base.Load( builder );
    }
}
Thank you in advance for any ideas.
Coordinator
Apr 22, 2013 at 5:35 AM
A model binder should never do that sort of thing. Its role is to map inputs to objects, not to do database access.
Jan 29, 2014 at 10:52 AM
Even though the initial example might be flawed, the question is still relevant. We're trying to inject some site settings into our model binder and need to do that on a per-request basis.

Using plain Autofac there's support for that from version 3 onwards: http://alexmg.com/model-binder-injection-in-autofac-aspnet-mvc-3-integration/. But I haven't seen any of that in Orchard. Do you see any architectural problems using this approach with Orchard's per-tenant setup? Or is there maybe an even easier solution?

What about passing the root lifetime into the model binder instance and creating new child lifetimes on a per call basis? Just, I don't know how to get that from inside our IOrchardShellEvents.Activated handler.

Please advise.
Coordinator
Feb 16, 2014 at 11:04 PM
Edited Feb 16, 2014 at 11:05 PM
My answer would still be the same: model binders are about mapping form fields, querystring parameters, cookies, etc. from their HTTP representation to an object or list of parameters. That mapping should never depend an anything else than the parameters themselves, only on the structure of the data.

If you think you need site settings, or anything from the database for that, you are misusing model binders. First, bind the parameters to an object or parameter structure, and then, from within your action, driver method or whatever it is, interpret that data any way you want. But that is and should remain a separate operation.

As an aside, this is also why it's almost never necessary to define your own model binders, because there are only so many useful data structures to be mapped.
Feb 18, 2014 at 11:01 AM