I'm studying about Dependency Injection, and I need some help to a better understand about Controller Factory.
I need inject the SqlReceitaRepository via Constructor Injection in HomeController.
HomeController Constructor
private readonly IReceitaRepository repositorio;
public HomeController(IReceitaRepository repositorio)
{
if (repositorio == null)
throw new ArgumentException("repositorio");
this.repositorio = repositorio;
}
With SqlReceitaRepository implemented, I can now set up ASP.NET MVC to inject
an instance of it into instances of HomeController, but how can I do that ?
Detail: I'm using NHibernate instead Entity Framework.
If needed, the classes that will be created for accomplish this, will belong which layer ?
I read some articles and I saw that I need put a new line in my Global.asax
Global.asax
var controllerFactory = new ReceitaControllerFactory();
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
I'm assuming that ReceitaControllerFactory should contain the IControllerFactory implementation.
But looking at the IControllerFactory
public interface IControllerFactory
{
IController CreateController(RequestContext requestContext, string controllerName);
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
void ReleaseController(IController controller);
}
We can see the method CreateController, but how can I inject a instance of SqlReceitaRepository into HomeController's instance?
The simple answer:
IController CreateController(RequestContext requestContext, string controllerName)
{
return new HomeController(new SqlReceitaRepository());
}
But, as you might have noticed, this will only work for one controller type as it is written. More importantly, it's not very maintainable. So the right answer is to get a popular DI framework like Ninject, and get the plugins you need for your frameworks (Ninject MVC, e.g.), and then define your bindings and let the framework take care of figuring out the dependencies:
Bind<IReceitaRepository>().To<SqlReceitaRepository>();
Related
I have a new project where Windsor container is used for IoC.
Here is simplified code executed in Install
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<BaseController>().LifestyleTransient(),
Component.For<ISecurityManager>().ImplementedBy<SecurityManager>(),
Component.For<IAccountManager>().ImplementedBy<AccountManager>()
........)
}
Information that I found in official documenation is not enough for understand in detail these lines.
Classes.FromThisAssembly().BasedOn<BaseController>().LifestyleTransient(),
This line in Register method enables dependency injection to all classes in my application that are inherited from BaseController.
BaseController is included.
Injection will not be made to other classes than described above.
We show to container that lifetime of all controllers classes will be an instance.
Component.For<ISecurityManager>().ImplementedBy<SecurityManager>()
To all controllers registered above, if they have in constructor interface ISecurityManager will be injected instance of class SecurityManager.
Lifetime of this SecurityManager is singleton as default value. So after application start we will have only one instance of SecurityManager for all controllers till the end of application execution.
Are my ideas correct? It seems that not, at least because LifestyleTransient() for controllers seems to me strange and that injected objects will be singletons too.
From bottom to the top :
Lifetime of this SecurityManager is singleton as default value. So after application start we will have only one instance of SecurityManager for all controllers till the end of application execution.
Exactly this is going to happen.
It seems that not, at least because LifestyleTransient() for controllers seems to me strange and that injected objects will be singletons too.
Controllers are transient because they hold the HttpContext - they have the information about the current user request and the following response. This is why they are transients and not singletons - the HttpContext is per request and it is created every time a browser/client requests something.
So it is understandable why controllers have shorter lifespan than your other services. It greatly depends on the inner architecture of the application. If someone else has a better idea why - I am more than willing to learn.
The Register/Resolve/Release cycle of your controllers can be done by creating a custom controller factory and substituting the default :
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
if (_kernel.GetHandler(controllerType) != null)
{
return (IController)_kernel.Resolve(controllerType);
}
return base.GetControllerInstance(requestContext, controllerType);
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
}
and somewhere put :
container.Register(Component.For<IControllerFactory>().ImplementedBy<WindsorControllerFactory>());
My controllers too have singleton dependenices. In this way you can achieve a pipeline programming model - you funnel the request from the controller through a series of objects and than return the results.
If SecurityManager has something to do with Authentication or Authorization it maybe better to use the MVC default Filtering mechanisms like IAuthorizationFilter or AuthorizeAttribute. Of course this maybe data access filter and it may be reasonable to put it in a different object.
Did I answer your questions?
Problem
I'm using Unity as IoC and that worked fine, but as I keep adding functionality, it becomes increasingly difficult to pinpoint any errors, because Unity provides an error that is the symptom of the error, not the actual error:
"Message":"An error has occurred.","ExceptionMessage":"An error occurred
when trying to create a controller of type 'MyController'. Make sure that the
controller has a parameterless public
constructor.","ExceptionType":"System.InvalidOperationException"
Background
I have an MVC Web Api controller that has a dependency on a Manager instance (from domain):
public class MyController : ApiController
{
private IMyManager MyManager { get; set; }
public MyController(IMyManager myManager)
{
this.MyManager = myManager;
}
...
}
The above error occurs because IoC mapping of the IMyManager fails. As it fails, I have no parameter, meaning that MyController is called using a parameterless constructor, but since it doesn't exist (and shouldn't) I get the above error.
What I have tried
So, the error I get is not the 'real' error. The obvious thing is to make sure that every new implementation is registered under IoC, I checked and they are. I do it manually to keep things manageable (oh the irony!).
I do that like this:
container.RegisterType<IMyManager, MyManager>();
But, that's not the issue.
One fix I did was a circular dependency. I changed all involved constructors and methods to use property values, not instances.
I checked all involved classes and there are no longer any circular dependencies.
Yet, the problem still occurs.
The question
What can I do to find out the actual problem? Manually checking dependencies is way too much overhead, because the structure is an intricate web of deeper dependencies. And this will get worse as the app matures.
Alternatively, if Unity just always obscures these messages (without being able to fix that), are there alternatives out there that do provide worthwhile error information?
UPDATE
Per request, the full error message (though I don't think the stacktrace is very helpful):
{"Message":"An error has occurred.","ExceptionMessage":"An error occurred when trying to create a controller of type 'MyController'. Make sure that the controller has a parameterless public constructor.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Type 'MyProject.Web.Api.Controllers.MyController' does not have a default constructor","ExceptionType":"System.ArgumentException","StackTrace":" at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"}}
UPDATE 2
I dug a little deeper and checked all dependencies (they are pretty massive), but everything is registered and loaded correctly. There also aren't any circular dependencies, so as far as I can tell everything 'should' work. Since it doesn't I conclude that there's some error happening that is not being thrown up.
If the error says that you need a parameterless constructor, that suggests to me that Unity isn't registered for WebAPI, even though it is registered for your ASP.NET MVC application. If your IoC is working correctly, it shouldn't need a paramaterless constructor, because it should be able to resolve the dependencies that exist within your controller's constructor.
WebAPI has it's own pipeline to ASP.NET MVC for example WebAPI can be OWIN hosted, hence why it needs hooking up separately even if they exist in the same project.
You should hook your WebAPI to the dependency resolver within your UnityConfig, I believe that there is an example here: http://www.devtrends.co.uk/blog/using-unity.mvc5-and-unity.webapi-together-in-a-project
using Microsoft.Practices.Unity;
using System.Web.Http;
using System.Web.Mvc;
namespace WebApplication1
{
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
// Configures container for ASP.NET MVC
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
// Configures container for WebAPI
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
}
In the example above there are two lines for configuration, but they share the same container and thus the same bindings - you don't have to define them twice. If you ever came to separate the WebAPI project from the ASP.NET MVC one, then you would have to have a separate container and bindings.
In terms of finding the problem, or Unity hiding errors from you, in my experience this simply isn't the case. The error that you're experiencing is straight from ASP.NET MVC. In normal use without an IoC, you need a parameterless constructor... with an IoC it controls the creation of the controllers and thus resolves the dependencies.
I found it, the problem was that I am remaking existing code, in the same solution, meaning that there's going to be duplicate files with identical names.
In this particular case I had an interface that was exactly the same as a previously existing one. Somewhere deep in the code I used the wrong namespace, meaning that the IoC mapping was incorrect.
So, something like this:
I have:
old.managers.IMyManager
and
new.managers.IMyManager
What I was doing in the mapping was:
container.RegisterType<IMyManager, MyManager>();
where IMyManager in this case is new.managers.IMyManager, as it should be.
One of the consumers of this dependency expected IMyManager of namespace old.managers.
Updating the consumer to use the new namespace fixed it.
Don't forget this in your web.config
<system.web>
<compilation targetFramework="4.8" />
<httpRuntime targetFramework="4.8" />
<customErrors mode="Off" />
</system.web>
Missing the httpRuntime targetFramework="4.8" part will cause the parameterless public constructor error
I think you should add another constructor for your controller.
public MyController() {}
If it still error, you should check the components that register for Application_Start (in Global.asax). In UnityConfig.cs :
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IMyManager, MyManager>();
MvcUnityContainer.Container = container;
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
Make the default for controller.
public class UnityControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = null;
if (TypeHelper.LooksLikeTypeName(controllerName))
{
controllerType = TypeHelper.GetType(controllerName);
}
if (controllerType == null)
{
controllerType = this.GetControllerType(requestContext, controllerName);
}
return controllerType != null ? this.GetControllerInstance(requestContext, controllerType) : null;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
throw new ArgumentNullException("controllerType");
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
return MvcUnityContainer.Container.Resolve(controllerType) as IController;
}
catch
{
return null;
}
}
}
public static class MvcUnityContainer
{
public static IUnityContainer Container { get; set; }
}
In Application_Start() (Global.asax.cs and Global.asax)
UnityConfig.RegisterComponents();
i have external controller (for e.g. ExtController ) in another assembly ( folder config/extensions ).
Registration:
builder.RegisterControllers(assembly).Named<IController>(t =>
t.Name.Replace("Controller", string.Empty)
);
Getting a controller ( i have own controller factory ):
public override IController CreateController
(System.Web.Routing.RequestContext requestContext, string controllerName)
{
try
{
var ctrl = _base.CreateController(requestContext, controllerName);
return ctrl;
}
catch (HttpException htte)
{
Object ic = null;
if (_container.TryResolveNamed(controllerName, typeof(IController), out ic))
{
return ic as IController;
}
else
throw htte;
}
}
And if i doing request for this controller i get "root" autofac lifetime scope.
In other controllers i got "AutofacWebrequest" scope.
Could you help me ? Maybe is another way for controller creation from another assembly ?
Edit
I resolved my problem but i think is not the best way i can do it.
I changed from:
if (_container.TryResolveNamed(controllerName, typeof(IController), out ic))
to:
if ( (DependencyResolver.Current as Autofac.Integration.Mvc.AutofacDependencyResolver).RequestLifetimeScope.TryResolveNamed(controllerName, typeof(IController), out ic))
Unfortunately, if your integration point is a custom controller factory working against named services, you are probably stuck with what you have. You can use AutofacDependencyResolver.Current rather than casting DependencyResolver.Current yourself, but the principle will still be the same.
However, I did notice you didn't show what the base ControllerFactory is. It appears you have a sort of decorator pattern going with _base being called rather than base (without the underscore). The DefaultControllerFactory already runs controller instantiation through the dependency resolver. Of course, that would mean you need to not register controllers as named services and instead just register them with the standard RegisterControllers method.
Again, if you have to register them named (for whatever reason) and/or if the base call to CreateController isn't going through the standard DefaultControllerFactory, then what you have is correct. If you can stop registering controllers as named services, though, the standard dependency resolution pipeline will "just work" and you won't need all the extra code.
There is detailed documentation on Autofac MVC integration on the Autofac doc site.
I'm using StructureMap and ASP.Net Identity in my application. When I have this line in my Application_Start
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
and this is StructureMapControllerFactory:
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null && requestContext.HttpContext.Request.Url != null)
throw new InvalidOperationException(string.Format("Page not found: {0}",
requestContext.HttpContext.Request.Url.AbsoluteUri.ToString(CultureInfo.InvariantCulture)));
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
return ObjectFactory.GetInstance(controllerType) as Controller; throws a StructureMapConfigurationException exception saying:
No default Instance is registered and cannot be automatically determined for type 'IUserStore<Person>'
but if I remove ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); line everything goes fine so it's StructureMap's problem not my code.
I think the exception is clear. It's probably about the AccountController from the Identity template, which comes with 2 constructors.
StructureMap will use the most greediest constructor by default. The template comes with 2 constructors, one default constructor and one constructor with an ApplicationUserManager object.
Without StructureMap the default constructor is called and the ApplicationUserManager will be resolved using the service locator anti pattern.
StructureMap now must create the ApplicationUserManager and because this is a concrete type it will try. If it was an abstract it will throw the exception right there. The ApplicationUserManager however has a single constructor which needs an IUserStore<Person>. Because this is an abstract and the container has no registration of this type, StructureMap is unable to create the type for you.
To solve this you should remove the default constructor and Register the ApplicationUserManager and depending services which is at least some component which, implements IUserStore.
Edit:
While the solution you mentioned in the comments may work, this is not the preferable solution because of:
Having multiple constructors is an anti-pattern
You are now using the service locator anti pattern for resolving the ApplicationUserManager from the HttpContext
The templates that come with VS2013 need some work to use with dependency injection. This will cost some time. The good news is, it is possible and doable and will greatly improve your knowledge of Owin, Asp.Net Identity, Dependency Injection and SOLID design.
There are several blogs on how to start refactoring the templates to work with dependency injection. You could read about that here and here
I'm building an ASP .Net MVC 2 application and I want to follow the ideas from Mark Seemann's book "Dependency Injection in .Net" so I registered my custom Controller Factory in the Global.asax file and I'm configuring the container within the Controller Factory like so:
public IController CreateController(RequestContext context, Type controllerType)
{
var container = new Container();
object controller;
if(controllerType == typeof(MyControllerOne)
{
container.Configure(r => r.
For<IService>().
Use<ServiceOne>());
}
else if(controllerType == typeof(MyControllerTwo)
{
container.Configure(r => r.
For<IService>().
Use<ServiceTwo>());
}
......
return container.GetInstance(controllerType) as IController;
}
Now this code works (though it is possible I may have a mistake somewhere since I'm writing this by memory), the dependencies are being resolved and the correct controller is being instantiated with the correct dependency every time, but it seems that for every request the container is being configured to resolve the dependencies that will be needed at that moment. So my questions are:
Isn't that redundant?
Shouldn't the configuration of the container be done in the Global.asax as well so it is only done once? If so, how could this be done?
By configuring the container the way I'm doing it, how will object lifetime be affected? I mean, eventually there will be repositories that should have a singleton lifetime, some others should be created once by HTTP request, and so for. What could be the implications?
Any comments, ideas and/or suggestions will be much appreciated.
By the way, the IoC container I'm using is StructureMap though I think that for this particular question it might not be too relevant.
It is, indeed, redundant to conditionally register each controller upon request. With StructureMap, the Controller Factory should look like this:
public class StructureMapControllerFactory : DefaultControllerFactory
{
private readonly IContainer container;
public StructureMapControllerFactory(IContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
return (IController)this.container.GetInstance(controllerType);
}
}
All services should be unconditionally registered in a single container instance. As an example, you can register all Controllers with StructureMap like this:
this.Scan(x =>
{
x.AssemblyContainingType<HomeController>();
x.AddAllTypesOf<IController>();
x.Include(t => typeof(IController).IsAssignableFrom(t));
});
This is basically just following the Register Resolve Release pattern.