sample example about Dependency injection needs explanation - c#

I was going through this article about dependency injection http://www.asp.net/web-api/overview/advanced/dependency-injection
It shows Unity Container from Microsoft.
There are a few things that are not making sense to me
for example, following line
public ProductsController(IProductRepository repository)
The above is the constructor of Controller. I need to know who passes the repository to the constructor? ANd is that made possible by registering IProductRepository interface with Unity?
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
Is the above code is all needed to make MVC pass the object to the constructor of a controller?

You answered your own question:
is that made possible by registering IProductRepository interface with Unity?
Yes.
When you request to resolve a type using Unity, the container searches for public constructors. If the constructor needs some implementation (IProductRepository in your case), the container searches within its registrations for an implementation for all the needed parameters. If found, it resolves that. This is a recursive process.
So yes. You need to register an implementation of IProductRepository using the container in order to resolve an instance of the Controller using that container.

Related

How do IoC controllers actually work? Specifically in .NET MVC?

Controller Constructor:
IRestaurantData db;
public HomeController(IRestaurantData db)
{
this.db = db;
}
// Container code
public class ContainerConfig
{
internal static void RegisterContainer(HttpConfiguration httpConfiguration)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<InMemoryRestaurantData>()
.As<IRestaurantData>()
.SingleInstance();
var container = builder.Build();
// MVC CONTROLLER VERSION
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// WEBAPI CONTROLLER VERSION
httpConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
So I'm trying to wrap my head around how Inversion of Control containers work. The course I'm in is using Autofac to create these containers. From what I'm currently understanding creating this container is making it so that when I instantiate my HomeController with IRestaurantData the container is pointing the interface AT InMemoryResataurantData everytime it is used. I can understand that much. What Im also confused by is I dont understand WHERE in the program my Controllers are are actually being instantiated? Does anyone know?
That is being done by autofac. whenever you request a class from a container, it will instantiate the type for you using the default constructor. If you have a constructor with parameters, it will look in the container for other registered types and will instantiate a new object or fetch an already used object.
Your instantiated types can be transient (short lived) or not.
So in short; when the object is requested.

ASP.NET Core 2.1 Service Locator with Simple Injector returning null

I have an .NET MVC 5 .NET Framework Application which I am converting to .NET Core 2.1
I have a custom action filter which in .NET Framework version was registered as a Global Filter in a Filterconfig class like below:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyCustomActionFilter());
}
}
Within the custom action filter in the .NET version I was using Service Locator pattern (I know it can be considered an anti pattern) as below:
var myService = DependencyResolver.Current.GetService<IMyService>();
I am using Simple Injector for DI and everything works fine in the .NET Version. With the .NET Core version I am trying to get the same functionality working but myService is always null
I am still using Simple Injector (as all the other projects in the solution use it and they are not getting move to .NET Core projects (only the web one is).
My Startup.cs class has this code:
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter());
});
SimpleInjectorConfig.IntegrateSimpleInjector(services, container);
At my service layer I have a SimpleInjector Registartion class that gets called from Web Layer - it then calls down to DAL Layer to do Registration
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container)
{
container.Register<IMyService, MyService>();
//further code removed for brevity
When I run the application with a breakpoint in the Custom Filter and a breakpoint in this RegisterServices method I can see the breakpoint in the RegisterServices method gets hit first and then the breakpoint in the Custom Filter - this made me think everything was wired up in the container correctly.
However I am trying to do the below again in the custom filter with .NET Core Service Locator pattern
var myService = filterContext.HttpContext.RequestServices.GetService<IMyService>();
but the result is always null?
Is there something I have missed in this setup?
------------ UPDATE -------------------
Based on Stevens comment I added a constructor to my action filter and passed in the Simple Injector container.
So My Startup class now is:
public class Startup
{
//Simple Injector container
private Container container = new Container();
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter(container));
My Custom filter now is like below with constructor added:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//actual code of custom filter removed - use of MyService
I set a breakpoint on the Constructor of MyCustomActionFilter and I can see it getting hit but I get an Error thrown:
SimpleInjector.ActivationException: 'The IDbContext is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.'
MyService has a Dependency on the DbContext which is injected into it (it is doing work saving and retrieving data from DB.
For the DB Context I registered it as below:
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container, string connectionString)
{
container.Register<IDbContext>(() => new MyDbContext(connectionString),
Lifestyle.Scoped);
}
}
There are some significant changes between how to integrate Simple Injector in the old ASP.NET MVC and the new ASP.NET Core. In the old system, you would be able to replace the IDependencyResolver. ASP.NET Core, however, contains a completely different model, with its own internal DI Container. As it is impossible to replace that built-in container with Simple Injector, you will have the two containers run side-by-side. In that case the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you.
When you call HttpContext.RequestServices.GetService, you will be requesting the built-in container for a service, not Simple Injector. Adding the IMyService registration to the built-in container, as TanvirArjel's answer suggests, might seem to work at first, but that completely skips Simple Injector from the equation, which is obviously not an option, as you wish to use Simple Injector as your application container.
To mimic the Service Locator-like behavior you had before, you will have to inject the SimpleInjector.Container into your filter, as follows:
options.Filters.Add(new MyCustomActionFilter(container));
It would be an error, however, to call the container from within the constructor, as you are showing in your question:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>(); // NEVER DO THIS!!!
}
...
}
WARNING: You should never resolve from the container from the constructor. Or in more general: you should never use any injected dependency from inside the constructor. The constructor should only store the dependency.
As Mark Seemann explained, injection constructors should be simple. In this case, it even gets worse because:
During the time that the constructor of MyCustomActionFilter is invoked, there is no active scope, and IMyService can't be resolved
Even if IMyService could be resolved, MyCustomActionFilter is a Singleton and storing IMyService in a private field will cause a hidden Captive Dependency. This could lead to all sorts of trouble.
Instead of storing the resolved, IMyService dependency, you should store the Container dependency:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly Container _container;
public MyCustomActionFilter(Container container)
{
_container = container;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
myService = container.GetService<IMyService>();
//actual code of custom filter removed - use of MyService
}
}
During the time that OnActionExecuting is called, there will be an active Simple Injector Scope, which will allows IMyService to be resolved. On top of that, as IMyService is not stored in a private field, it will not be cached and will not cause a Captive Dependency.
In your question you referred to the Service Locator anti-pattern. Whether or not the injection of the Container into your filter is in fact an implementation of the Service Locator anti-pattern depends on where the filter is located. As Mark Seemann puts it:
A DI container encapsulated in a Composition Root is not a Service Locator - it's an infrastructure component.
In other words, as long as the filter class is located inside your Composition Root, you are not applying the Service Locator anti-pattern. This does mean, however, that you must make sure that the filter itself contains as little interesting behavior as possible. That behavior should all be moved to the service that the filter resolves.
As #Steven points out, the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you. For built-in container, it could not resolve the service from simple injector. For simple injector, you could try EnableSimpleInjectorCrossWiring to resolve services from built-in container.
For options.Filters.Add, it also accepts MyCustomActionFilter instance, without resigering Container as depedence into MyCustomActionFilter, you could try register MyCustomActionFilter in sample injector, and then pass this instance to options.Filters.Add.
Register Services
private void InitializeContainer(IApplicationBuilder app)
{
// Add application presentation components:
container.RegisterMvcControllers(app);
container.RegisterMvcViewComponents(app);
// Add application services. For instance:
container.Register<IMyService, MyService>(Lifestyle.Scoped);
container.Register<MyCustomActionFilter>(Lifestyle.Scoped);
// Allow Simple Injector to resolve services from ASP.NET Core.
container.AutoCrossWireAspNetComponents(app);
}
add MyCustomActionFilter
services.Configure<MvcOptions>(options =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
options.Filters.Add(container.GetRequiredService<MyCustomActionFilter>());
}
});
#region SampleInjector
IntegrateSimpleInjector(services);
#endregion
Note If you specify container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();, you will need using (AsyncScopedLifestyle.BeginScope(container)) when you call container.GetRequiredService<MyCustomActionFilter>().

Accessing unity container of web app from a class library

I have a class library for caching ( Redis ), we have a unity container inside this Redis class library
public class TCache<T>
{
static readonly IUnityContainer container = new UnityContainer();
private ITCache<T> ICacheStore;
static TCache()
{
container.RegisterType<ITCache<T>, TRedisCacheStore<T>>(new ContainerControlledLifetimeManager());
}
public TCache()
{
ICacheStore = container.Resolve<TRedisCacheStore<T>>();
}
Now my senior said me not use a separate container like this and I should be using the container which is already created inside the web app with the reason being that there should be only one single container.
My question is: is it possible to access a unity container that resides in a different project and is it necessary to do this change ?
Note: I cannot add the reference of the web app into the Redis cache class library.
You should only reference a container within your composition root (http://blog.ploeh.dk/2011/07/28/CompositionRoot/).
In other words, find where your current services are registered, and perform the generic registration there.
Your type that requires a cache store then takes your abstraction via constructor injection:
public class Cache<T>
{
private readonly ITCache<T> cacheStore;
public Cache(ITCache<T> cacheStore)
{
this.cacheStore = cacheStore
?? throw new ArgumentNullException(nameof(cacheStore));
}
}
By the way, using T as a prefix for your types (rather than as a prefix for generic type parameters) is very confusing.
The names TCache and ITCache are also very confusing.
Well, I share his view of the usage of the container. How I fixed this issue is (without going into the details of how I actually created it):
Make an option to register onto the container through an interface. Something like IRegisterContainer.Register(IUnityContainer container).
Then at the moment where you now register the mappings to the container, you extend that function to also search your assembly for all objects that implement that IRegisterContainer and make them register themselves.
And use this as a platform to fix your problem.
If you want to use the IUnityContainer in your TCache object to resolve the TRediscacheStore. Simply let the IUnityContainer register itself.
container.Register<IUnityContainer, container>().
And make it a dependency in the constructor of TCache.

ASP.NET Core MVC Dependency Injection via property or setter method

It has been well documented, how to inject dependencies into services.
Question: But is it (already) possible in ASP.NET Core 2.0 to have the system's DI mechanism automatically inject a service into a method or into a property?
Sidenote: In PHP-Symfony this pattern is called setter injection.
Example:
Say I have a common MyBaseController class for all controllers in my project and I want a service (e.g. the UserManager service) to be injected into MyBaseController that can be later accessed in all child controllers. I could use constructor injection to inject the service in the child class and pass it via base(userManager) to the parent. But having to perform this in all child constructors of all controllers is pretty tedious.
So I would like to have a setter in MyBaseController like this:
public abstract class MyBaseController : Controller
{
public UserManager<User> userManager { get; set; }
// system should auto inject UserManager here
public void setUserManager(UserManager<User> userManager) {
this.userManager = userManager;
}
}
...so I don't have to do the following in every child constructor just to pass the dependency to the parent:
public class UsersController : MyBaseController
{
public ChildController(UserManager<User> userManager) : base(userManager) {}
Update: The answer given here is what I want to achieve, however the question was asked for ASP.NET Core 1.0, I'm interested in whether any solutions have been added in ASP.NET Core 2.0.
In general it is good advice to avoid non constructor DI as it is considered a bit of an anti pattern, there is a good discussion about it in this related question.
With the default Microsoft.Extensions.DependencyInjection container in aspnet core, the answer is no, but you could swap to something more powerfull like autofac (which has property injection) if you are sure you really need this feature.
You can perform setter injection with the built-in DI container (Microsoft.Extensions.DependencyInjection) using Quickwire. Unlike Autofac, this is not a new DI container, it just extends the default one.
To make it work:
Add this to ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
// Activate controllers using the dependency injection container
services.AddControllers().AddControllersAsServices();
services.ScanCurrentAssembly();
// ...
// Register your other services
}
By default, ASP.NET Core will activate controllers by instantiating them directly without going through the DI container. Fortunately, this behaviour can easily be overridden to force ASP.NET Core to resolve controllers using dependency injection. This is what services.AddControllers().AddControllersAsServices() does.
ScanCurrentAssembly is necessary to get Quickwire to search for services declared in your assembly and register them (which will include your controllers).
Decorate your child controller with [RegisterService]
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
This will make your ChildController discoverable when ScanCurrentAssembly is called in step 1.
Decorate the setter
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
Now the UserManager property in your child controller will be automatically set from the dependency injection container.
You have two kind of DI
Mandatory, it's injection needed for object initialization then it's injection setted in constructor.
Optional, it's injection needed for action.
If DI is doing well, u can have unit test without injection system, if all injections are in ctor then you'll break every unit test, every time for nothing.
So all injections in ctor break open/close principle.
One more point is DI is for interface implementation or module public part, object under this implementation are initialized manually.
So setter is not bad because there are hidden by interface.

Is it possible to get current Unity container inside controller

I registered unity container like this:
var container = new UnityContainer();
container.RegisterType<ICacheManager, CacheManager>(new ContainerControlledLifetimeManager())
Is it possible to get access to this "container" from controller
Not sure why you need that, but here's the code:
public ActionResult Area51()
{
var _service = DependencyResolver.Current.GetService(typeof (IDummyService));
return View();
}
If what you are trying to do is injecting a Controller, you should set DepedencyResolver to use your IoC container in Global.asax's application start. Then, MVC will inject dependency to your controller automatically.
var container = new UnityContainer();
DependencyResolver.SetResolver(new Unity.Mvc4.UnityDependencyResolver(container));
Look here for more example:
http://www.dotnet-tricks.com/Tutorial/dependencyinjection/632V140413-Dependency-Injection-in-ASP.NET-MVC-4-using-Unity-IoC-Container.html
I'm assuming you're resolving some Controller instance using the container. If that's the case, you can have the controller receive the IUnityContainer as a dependency just like any other.
What are you trying to accomplish? Getting the container in your resolved classes is not great because it couples your classes with the container, and can usually be replaced with other mechanisms.
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var foo = container.Resolve<MyController>();
}
}
public class MyController
{
private IUnityContainer container;
public MyController(IUnityContainer container)
{
this.container = container;
}
}
One way of doing this which I often do for convenience is to declare your container as a global variable in your Global.ascx.cs file like:
public class MvcApplication : System.Web.HttpApplication
{
public static UnityContainer Container;
protected void Application_Start()
{
// assuming your initialize here
}
}
However this is fairly hack-ish.
The correct thing to do would be to use Unity to resolve your Controllers (See this article on creating a unity controller factory), and then allow unity to inject any dependencies into your controller when it resolves the controller.
So a controller like:
public MyController: Controller {
public ICacheManager CacheManager {get;set;}
}
Would automagically resolver any dependencies that your container has registered.
Although it is possible to that, it's best that you avoid it.
It's best that you take any dependencies the controller needs via constructor parameters. This way, the class (controller) makes it clear what are the dependencies required for it to run.
If configured correctly, the container will provide those dependencies and their dependencies (if any), and so on.
The usage of an IoC container should typically be restricted to only one place inside an application (called the composition root). Any extra reference/call to the container is susceptible to lead to the Service Locator anti-pattern. See the linked article for reasons why such an approach may be bad.

Categories