Using Autofac with Mvc controller constructor injection - c#

I'm having trouble with Autofac constructor injection. I'm somewhat solved my problem but I'm turning to the community for a full solution.
This works with DI
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.InstancePerHttpRequest();
This does not.
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.AsImplementedInterfaces()
.InstancePerHttpRequest();
Here's my controller.
public class HomeController : BaseController
{
public HomeController(IPlugin plugin)
{
}
}
I have a module to resolve the IPlugin injection. I'm wondering why I need to take the .AsImplementedInterfaces() out to make this work. I would prefer to use interfaces because I'm using MEF to import IControllers from other assemblies at runtime.
Update
Thanks to japonex (see comments below) I've updated my solution. Here's what I did to get everything working.
First my project has its own controllers, and I then use MEF to import controllers from other assemblies.
Controllers for my current project must be registered without the .AsImplementedInterfaces() call, so like so
builder.RegisterControllers(typeof(MvcApplication).Assembly).InstancePerRequest();
This will put the controllers into Autofac using the type instead of as an interface (MyProject.Controllers.HomeController instead of System.Web.Mvc.IController).
Next in my plugin project I simply had to export the types instead of as an interface.
So I use this
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : PluginController
Instead of this
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : PluginController
Notice the difference in the Export attribute.
Next I set the current DependencyResolver to the AutofacDependencyResolver.
Last, but not least, I created a custom ControllerFactory to create the controllers. Technically this isn't needed, since I'm no longer using interfaces, but I have code to check the status of the controller before creating it. This allows me to easily enable/disable a plugin from an admin area.
So the root of the problem is that Autofac needed types instead of interfaces to resolve properly. I'm sure this could be done with interfaces, but this solution works for me. The only real reason I would have wanted to use interfaces is because I could then ask for all controllers from Autofac without knowing their type.
public class MyControllerFactory : DefaultControllerFactory
{
private readonly IContainer _container;
public PortalControllerFactory(IContainer container)
{
_container = container;
}
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
Type controllerType = GetControllerType(requestContext, controllerName);
if(controllerType == null)
{
throw new HttpException(404, ErrorMessages.Http404);
}
IPlugin plugin = PluginManager.Current.GetPlugin(controllerType);
if (plugin != null && plugin.Status != Common.Enums.PluginStatus.Enabled)
{
//the controller/plugin is disabled so modify the route data and return the controller
RouteData data = new RouteData();
data.Values.Add("controller", "plugin");
data.Values.Add("action", "disabled");
data.Values.Add("plugin", plugin.Name);
requestContext.RouteData = data;
return ViewRenderer.CreateController<Project.Controllers.PluginController>(data);
}
var controller = ((AutofacDependencyResolver)DependencyResolver.Current).RequestLifetimeScope.Resolve(controllerType);
return controller as IController;
}
}

When you use .AsImplementedInterfaces you're saying that for each concrete type, Autofac registers this type for each interface implementation.
So, you're registering all controllers in your Assembly to IController and propably because you don't have any rule (keyed or named registration) to decide which concrete type return, Autofac probably returns the last registration for IController.
Try call container.Resolve and see what you get.
Consider that if you have:
public class HomeController : BaseController
{
public HomeController(IPlugin plugin)
{
}
}
and
public class Home2Controller : BaseController
{
public Home2Controller(IPlugin plugin)
{
}
}
HomeController will be registered to IController and the
Home2Controller also will be registered to IController.
And I think the default behavior of Autofac is to use the last registration if you don't use any kind of rule (keyed or named registration)

Related

Registering AccountController with Unity IoC

Account Controller does not Register correctly
I have an ASP.NET MVC application with Individual user accounts using Identity. In my account controller I have a UserMappingService that I would like to inject.
There are two AccountController constructors, the one that was originally an empty constructor is the one that is causing issues. I need to inject the UserMappingService here. Before I added the Service to the parameters of the constructor I was able to make the controller register the empty constructor by adding this to the UnityConfig.cs
//parameterless constructor in AccountController.cs
public AccountController()
{
}
// From UnityConfig.cs in RegisterTypes method
container.RegisterType<AccountController>(new InjectionConstructor());
The problem is that once I add the service as a parameter, I get errors.
private IUserMappingService userMappingService;
//constructor with interface in the parameter AccountController.cs
public AccountController(IUserMappingService mappingService)
{
userMappingService = mappingService;
}
//From UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IUserMappingService, UserMappingService>();
container.RegisterType<AccountController>(new InjectionConstructor());
}
Resulting error upon runtime is:
Error in RegisterType(Invoke.Constructor())
ArgumentException: No member matching data has been found.
I am pretty sure the (InjectionConstructor) is only good for for the default parameterless constructor, but I don't know how else to Register the controller in this case.
You can spec the dependency type like this:
var ctr = new InjectionConstructor(typeof(IUserMappingService));
container.RegisterType<AccountController>(ctr);
Or you can flag your constructor with InjectionConstructorAttribute:
[InjectionConstructor]
public AccountController(IUserMappingService mappingService)
{
userMappingService = mappingService;
}

Fluent Validation and Ioc container: CreateInstance called many times in MVC web application

In the MVC project im working I use Fluent Validation to implement some validation logics and I defined my UnityValidatorFactory as following:
public class UnityValidatorFactory : ValidatorFactoryBase
{
private readonly IUnityContainer _container;
public UnityValidatorFactory(IUnityContainer container)
{
_container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
if (_container.IsRegistered(validatorType))
{
return _container.Resolve(validatorType) as IValidator;
}
return null;
}
}
In global.asax i register my class like this:
var validationFactory = new UnityValidatorFactory(container);
var fluentValidationModelValidatorProvider = new FluentValidationModelValidatorProvider(validationFactory);
I defined my validator for my viewmodel:
public class ServiceRequestViewModelValidator : AbstractValidator<ServiceRequestViewModel>
{
public ServiceRequestViewModelValidator()
{
// many validation rules here...
}
}
I register my validator in unity:
container.RegisterType<IValidator<ServiceRequestViewModel>, ServiceRequestViewModelValidator>();
When i post data to the action with argument of type ServiceRequestViewModel the method CreateInstance is called so many times and the
constructor of ServiceRequestViewModelValidator as well.
Because the validatin rules I implemented are time consuming I don't wont they get executed more then one time. Moreover I don't understand why they are call more than one time.
I later found out that this is how MVC works. In MVC there are many place where MVC needs to get the validator for example it tries to get metadata for each property, and calls into the provider for each one.
Then to fix my problem I created my validators as singleton instances registering the validator in unity with ContainerControlledLifetimeManager
container.RegisterType<IValidator<ServiceRequestViewModel>, ServiceRequestViewModelValidator>(new ContainerControlledLifetimeManager());

Object reference not set to an instance of an object error!

Can anyone see what I'm doing wrong here? I'm trying to learn how to have specs/ services and domain projects in general but in this case it's ASP.NET MVC.
I have the following code in my controller but I getting Object reference not set to an instance of an object on the following line of code. I would appreciate any suggestions where I'm going wrong!?
// Error
Line 22: var profiles = _profileService.GetProfile();
// code below
namespace Whitepages.Controllers
{
[HandleError]
public class HomeController : Controller
{
private readonly IProfileService _profileService;
public HomeController(IProfileService profileService)
{
_profileService = profileService;
}
public HomeController()
{
}
public ActionResult Index()
{
var profiles = _profileService.GetProfile();
return View("Index");
}
}
}
using Domain;
namespace Services.Spec
{
public interface IProfileService
{
Profile GetProfile();
}
}
Many thanks,
It looks like the controller factory you are using to build your controllers passes null at the constructor of HomeController. In ASP.NET MVC controllers are built by a controller factory which by default is the DefaultControllerFactory class which simply invokes the default constructor.
The fact that you are getting a NullReferenceException instead of the class HomeController doesn't have a default constructor indicates that you have setup a custom controller factory in your Global.asax which is supposed to provide instances of your controllers but this custom controller factory doesn't passes null to the HomeController constructor, so when later you try to access this service _profileService.GetProfile() you get the exception. You are probably using some dependency injection framework and in your Application_Start you have something like this:
ControllerBuilder.Current.SetControllerFactory(new SomeCustomControllerFactory());
So if you are using a DI framework you need to setup this framework to pass a specific implementation of the IProfileService interface to the constructor. How this is done would totally depend on the framework you are using.

MVC 3 beta + Dependency Resolver + Unity = got problem

I'm tried to use Dependency Resolver with Unity, and got some problem when my Controller creating.
Here example of controller:
public class AccountController : Controller
{
private readonly ICourseService _courseService;
public AccountController(ICourseService courseService)
{
_courseService = courseService;
}
}
But, when Controller try to create - i got an exception "No parameterless constructor defined for this object." I even try to add default constructor for this controller, but courseService didn't create. Also try to add property with [Dependency] attribute - nothing happened.
Here is Dependency Resolver class:
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.ResolveAll(serviceType) : new List<object>();
}
}
and Global.asax.cs:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var container = new UnityContainer();
container.RegisterType<ICourseService, CourseService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
Can anyone help me ?
Old post but these other answers are flat out wrong. Had this problem myself today, and you definitely do not need to register the controllers or a controller factory. This message just means that something in the dependency hierarchy for the controller is not registered. E.g. If your controller requires IService in it's constructor and IService requires IRepository in its constructor, but you forgot to register IRepository you will get this error.
Your IDependencyResolver implementation requires that AccountController is registered. Try adding this registation otherwise it will return null and MVC will try to create the controller with the Activator which requires a parameterless ctor.
The code above will break if your controllers have dependencies on non registered types that are concrete. You should modify the GetService() to the following:
public object GetService(Type serviceType){
if (!container.IsRegistered(serviceType)){
if (serviceType.IsAbstract || serviceType.IsInterface){
return null;
}
}
return container.Resolve(serviceType);
}
That way if say CourseService has a dependency on the concrete CourseRepository, the container will instantiate it.
I'm with DanH in the assumption that somewhere in the hierarchy there is a missing type registration, or a dependency on a concrete type that is not getting instatiated.
I had this same issue, and found the following article helpful:
http://xhalent.wordpress.com/2011/01/17/using-unity-as-a-dependency-resolver-asp-net-mvc-3/
Your problem is that MVC is still attempting to instantiate the controller with the default controller factory, which requires a parameter-less constructor, and has no knowledge of your Unity container or how to resolve the ICourseService dependency.
You need to build a custom controller factory to take advantage of Unity (specifically one that overrides GetControllerInstance(Type type) - there should be plenty of documentation and samples around for this; it's a straightforward class - and then register it in Application_Start as follows:
ControllerBuilder.Current.SetControllerFactory (new MyUnityControllerFactory(container));

Database injection into a validation attribute with ASP MVC and Castle Windsor

I need some help - I am trying to use a custom validation attribute in an ASP.NET MVC web project that needs to make a database call.
I have windsor successfully working for the controllers and the IRepository interface is injected normally. The problem arrises when I need to inject the repository into the attribute class.
The attribute class has the following code:
public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
private readonly string message;
private readonly IArticleRepository articleRepository;
public ValidateUniqueUrlNodeAttribute(string message)
{
this.message = message;
}
public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
{
this.articleRepository = articleRepository;
}
public override IValidator Build()
{
var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };
ConfigureValidatorMessage(validator);
return validator;
}
My problem is that I cannot seem to make Windsor intercept the contruction of the attribute to pass in the IArticleRepository
The current code in my global.asax file is as follows:
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
container
.RegisterControllers(Assembly.GetExecutingAssembly())
.AddComponent<IArticleRepository, ArticleRepository>()
.AddComponent<ValidateUniqueUrlNodeAttribute>();
Any help would be greatly appreciated.
AFAIK no dependency injection container can directly manage an attribute, since it's instantiated by the runtime and there's no way to intercept that.
However, they can cheat by either:
Using a static gateway to the container (example), or
Using a "BuildUp" feature that injects whatever dependencies are found within an already-constructed object. This is called BuildUp in Unity or InjectProperties in Autofac.
Windsor doesn't support #2 (ref1, ref2), so you can either:
Try one of the hacks to make Windsor support #2 (hack1, hack2)
Use a static gateway
Implement your own IValidatorBuilder and make it use Windsor to create validators. I'm sure this is implemented somewhere but I can't find it right now...
Don't know if this helps, but I subclassed ValidationAttribute to expose a Resolve<T>() method like so:
public abstract class IocValidationAttribute : ValidationAttribute
{
protected T Resolve<T>()
{
return IocHelper.Container().Resolve<T>();
}
}
Then it can be used in any custom ValidatorAttribute that needs to hit a database:
public class UniqueEmailAttribute : IocValidationAttribute
{
public override bool IsValid(object value)
{
ICustomerRepository customerRepository = Resolve<ICustomerRepository>();
return customerRepository.FindByEmail(value.ToString()) == null;
}
}
I think it's a variation of the 'Static Gateway' approach mentioned by Mauricio Scheffer. I don't know if this is a good design or not. I'm not a huge fan of it, I'd rather the dependency was injected more 'elegantly', though I can't use constructor injection obviously, I'd like to use Property injection but can't work out a way to hook into the ASP.NET MVC framework code to do this (I've even pored though the MVC2 source code).
I was able to wire it up [using Autofac as it happens, but it's just constructor injection via the ASP.NET MVC DependencyResolver] in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
Hmm.
Can you test the effect of removing the (string message) ctor, and see if that at least forces Castle to use the ctor with the Repostiory ?
Otherwise we call AddComponent(name, type, type). Other than that it really should work...
Also does this hint at my first idea ? How do I use Windsor to inject dependencies into ActionFilterAttributes

Categories