简体   繁体   中英

MVC Controller Generic injection with AutoFac

I am fairly new to DI with Autofac and wonder if the following is possible

I want to create a generic controller and action that receives an injected type. I do not want an instance of the injected type, but just need its type, which would be an inplementation of an expected interface.

I would also like to pass that generic type on to a ViewModel, but that is another subject altogether, however if some genious out there can solve both that would be excellent.

public ContractorController<T> : Controller 
    where T : IContractor{ 

    public ViewResult New() { 
            var vNewModel = new NewViewModel<T>(); 
            return View(vNewModel); 
        } 
} 

This controller should be called through http://mysite.com/Contractor/New

I have been looking into registering generics with AutoFac, but it seems that the problem is that the AutofacControllerFactory only implements GetControllerInstance(), expecting the controller Type passed to it from either GetController() or CreateController(), not sure which or what the diffirence is between them. These methods receive the controller's name as a string from RoutData and return the corresponding .NET type which, give the url, http://mysite.com/Contractor/New is controller=Contractor and thus ContractorController cannot be matched by GetController() or CreateController() and therfore passing null to GetControllerInstance() which mean AutofacControllerFactory does not attempt to resolve the type.

I figured that I would have to create a custom Controller Factory deriving from AutofacControllerFactory, override GetController() or CreateController() and perform my own mapping from the controller names to the generic types. Something like

if (controllerName == "Contractor") return System.Type.GetType( "UI.Controllers." + controllerName + "Controller`1");

When I debug this I can see that this code is finding the generic controller and returning it.

I thought I could then just register the types like

builder.RegisterType<FakeContractor>().As<IContractor>(); 
builder.RegisterGeneric(typeof(ContractorController<>)); 

But I am getting the following error

The Autofac service 
'UI.Controllers.ContractorController`1' 
representing controller 
'ContractorManagement.UI.Controllers.ContractorController`1' 
in path '/Contractor/New' has not been registered. 

So I think I may be barking up the wrong tree. Can anyone please shed some light on how I can do this without pulling my teeth

Thank you

I'm not entirely sure why you want a controller using a generic. Using a generic on a Controller isn't really supported in Mvc - or at least the supporting routing path would be involved. Perhaps you can provide more info on the reasoning behind the approach?

What it looks like is that you want a controller that supports model binding against varying types. The next question is whether these types vary across a common interface or base class.

If that's the case, for Mvc2 check out the IocModelBinder information . This will work with Autofac quite well. This will allow the type to be model bound on post or get allowing you to inject services with autofac.

If you want to vary the types by a common base - supporting a variety of concrete view model - then check out the DerivedTypeModelBinder in MvcContrib . There is a version that works in Mvc 1, 2 and now MvcContrib for Mvc3 has a good sample app to accompany it. The Mvc3 implementation is also faster - speed wasn't a problem before, it's just a more efficient identification process.

Maybe it's not a direct answer to your question, but this is the only possible way to use generic controllers that I ever seen and used:

public abstract class ContractorControllerBase<T> : Controller where T : IContractor { 
    public ViewResult New() { 
        var vNewModel = new NewViewModel<T>(); 
        return View(vNewModel); 
    } 
} 

public class FakeContractorController : ContractorControllerBase<FakeContractor> {
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM