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.
Related
I am trying to setup dependency injection in my ASP.NET MVC 5 app using Unity.Mvc. I followed this tutorial which explains that the class UnityConfig has a method called RegisterTypes which allows me to register my type into the container.
However, I am using Area in my project. some of my Areas need to be able to also register types into the container. These types in my area will only be used by my area but still need to be registered.
How can I register-types into my IoC container directly from my area?
You can create a separate class that inherits from UnityContainerExtension and place it in your area, like this:
public class MyAreaContainerExtension : UnityContainerExtension
{
protected override void Initialize()
{
Container.RegisterType<IDoesSomething, DoesSomething>();
}
}
Then in your startup,
container.AddNewExtension<MyAreaContainerExtension>();
Or if your extension has constructor parameters you pass to it, like configuration data it needs or instances it should use, you can create an instance of the extension and then do
container.AddExtension(theExtensionInstanceICreated);
It's a nice practice because it allows you to keep component registration closer to the classes being registered instead of having one gigantic file with dozens or even a hundred or more registrations.
Another benefit of this approach is that as component registrations become complicated you can write unit tests for these extensions that add the extension to a container and then resolve objects from the container.
You could have other components which must be registered in order for the types registered in this extension to work, but you don't want to duplicate the registrations in your extension. In that case you could make it explicit by specifying what types must already be registered, something like this:
public class MyAreaContainerExtension : UnityContainerExtension
{
protected override void Initialize()
{
AssertRequiredRegistrations();
Container.RegisterType<IDoesSomething, DoesSomething>();
}
private void AssertRequiredRegistrations()
{
AssertRequiredRegistration(typeof(ISomeOtherType));
}
private void AssertRequiredRegistration(Type type)
{
if(!Container.IsRegistered(type))
throw new Exception($"Type {type.FullName} must be registered with the container.");
}
}
I am facing problem with disposing unnecessary objects from DI container. I use Prism for Xamarin.Forms with Unity container.
Application gets configuration from some database, creates some services using this configuration and registers this services in container using ContainerControlledLifetimeManager. This services are used while resolving views and viewmodels.
When configuration changes application retrieves again changed configuration and now problem comes: how can I remove previous registrations and register new services? If I simply re-register service then previous service is not GC-ed until disposing container.
I cannot dispose container, because it is created and managed by Prism (can I?).
I cannot use child container because Prism will not resolve views and viewmodels using child container (can I?)
Should I use different DI? Does Autofac or other DI support such approach?
EDIT:
I just have tested disposing of re-registered objects in Unity. It came out that re-registering using:
Container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager())
really releases previously registered objects. But I have also registrations using just type:
Container.RegisterType<Foo>(new ContainerControlledLifetimeManager())
or using instance:
Container.RegisterInstance(new Foo())
and these objects are not released when re-registering.
So now the only solution is to reconstruct the Unity container? Or give a try to other ioc container?
Without knowing all of the specifics of what you are looking to accomplish it's impossible to give you a solid roadmap, so I'll touch on some things to consider.
Reregistering Services
If you have some service IFoo, and two implementations FooA and FooB and you initially registered FooA as the implementation for IFoo (with a container controlled lifetime, registering FooB with the container should dispose of the FooA instance and FooB should be generated going forward.
Reconstructing the container
If you have to reconstruct the Container, it should possible. I haven't ever run into a use case where I have had to try something like what you are looking to do. For starters you probably want to take a look at the Initialize method from PrismApplicationBase. This is where the container gets constructed and setup. To handle the reconstruction, you will want to create an event that you subscribe to in your App class.
public partial class App
{
protected override void OnInitialized()
{
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent);
// navigate
}
private void OnSettingsChangedEvent()
{
var ea = Container.Resolve<IEventAggregator>();
// prevent a memory leak
ea.GetEvent<SettingsChangedEvent>().Unsubscribe(OnSettingsChangedEvent);
// If you need platform specific types be sure to register either the
// IPlatformInitializer or some similar helper
var platformInitializer = Container.Resolve<IPlatformInitializer>();
ModuleCatalog = CreateModuleCatalog();
ConfigureModuleCatalog();
Container = CreateContainer();
ConfigureContainer();
// This would be your original RegisterTypes, so this assumes you
// look at your settings when initially registering types.
RegisterTypes();
// See notes above
platformInitializer.RegisterTypes(Container);
NavigationService = CreateNavigationService();
InitializeModules();
// Your container is now reset.
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent>()
}
}
Containers
As for choosing a container. There is nothing wrong with Unity. Just know that when you're working with Unity, you're going to be stuck with the way it is since it apparently it is a dead project now. Ninject for Prism Forms uses a PCL variant that doesn't seem to be maintained anymore, but when the switch to NetStandard is made Prism will be able to target the current version of Ninject. As for Autofac, there you are dealing with an immutable container so the moment you resolve something you cannot update any new registrations. Autofac for Prism Forms is also a version behind for the same reason as Ninject. DryIoc for Prism forms is a great container and actually the one I am using on all of my current projects. It is also being actively maintained so you can expect use cases you run into to at least be heard.
Thanks for help to Dan S. and R. Richards.
Recreating Prism container caused problems in navigation. Maybe it is possible to fix it but I do not know how.
Using different IOC container would require too much time to learn it.
I ended up with custom lifetime manager (the solution provided in R. Richards link):
class CustomLifetimeManager : LifetimeManager
{
private object _Value;
public override object GetValue()
{
return _Value;
}
public override void RemoveValue()
{
_Value = null;
}
public override void SetValue(object newValue)
{
_Value = newValue;
}
}
Above lifetime manager allows to remove registrations:
public static class UnityContainerExtension
{
/// <summary>
/// Removes registrations that were registred using <see cref="CustomLifetimeManager"/>
/// </summary>
/// <param name="container"></param>
public static void RemoveCustomLifetimeRegistrations(this IUnityContainer container)
{
var registrations = container.Registrations.Where(r => r.LifetimeManagerType == typeof(CustomLifetimeManager));
foreach(var r in registrations)
{
r.LifetimeManager.RemoveValue();
}
}
}
I'm experimenting with IoC in my Web App and would like to do things according to best practices. Recently I discovered an IoC framework called DryIoc which is supposed to be small and fast.
I've read through the examples but none seem to point out where I should put the container itself.
Should it reside in the controller? Or in Global.asax? Someplace else maybe? Or perhaps as a static variable in a class?
I'd appreciate if someone would be able to guide me in the right direction, preferrably with some sample code, as I've stalled and don't got a clue on how to continue.
var container = new Container(); // Should obviously NOT be a local variable
container.Register<ISalesAgentRepository, SalesAgentRepository>(Reuse.Singleton);
Usually I do the following:
1 - Create a bootstrapper class
public static class Bootstrapper {
public static Container _container;
public void Bootstrap() {
var container = new Container;
// TODO: Register all types
_container = container;
}
public static T GetInstance<T>() {
return _container.Resolve<T>();
}
}
2 - Call the bootstrap method in the global.asax, in the Application_Start method:
protected void Application_Start() {
Bootstrapper.Bootstrap();
}
And never use the container anywhere directly, you have to hook it somewhere in the MVC lifecycle, and usually the DI package you use can do this for you.
Also note that I've added a GetInstance<T> method to the bootstrapper-class. This method is what makes it possible to use the container directly by requesting instances of types. I've added this method so you know it is possible, but always use constructor-injection if possible.
Actually, you may not need to store container on your side. Here is the DryIoc WebApi Owin sample.
The DryIoc.WebApi extension will store and Dispose the container when it is appropriate in IDependencyResolver implementation.
I can't seem to register my Castle Windsor objects by convention and I'm really at a loss. The situation is I have two projects, Website (a really basic web forms project) and BusinessObjects (a class library). I'm attempting to use IoC to be able to keep all of my business object implementations internal, and only deal with the interfaces in the Website project.
The best way that I've found to accomplish this is to use installers. So, in my Global.asax.cs I have this:
private IWindsorContainer _container;
public override void Init()
{
base.Init();
InitializeIoC();
Global.WindsorContainer = _container;
}
private void InitializeIoC()
{
_container = new WindsorContainer();
_container.Install(new BusinessObjectsInstaller());
}
public static IWindsorContainer WindsorContainer { get; private set; }
Which seems to work just fine, and to pull an object out of the container, I'm just using a very simple:
var thingey = Global.WindsorContainer.Resolve<IThingey>();
And then in my BusinessObjects project, I have this:
public class BusinessObjectsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IThingey>().ImplementedBy<Thingey>());
}
}
Now, at this point, everything is working as I expect it to. It's not elegant or anything, but I'm still trying to get a handle on this. So the big thing I'm trying to accomplish at this point is to wire these objects up in a more useful way, which lead me to replacing the above component registration with this:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IThingey>()
.LifestyleTransient()
);
Which I absolutely cannot get to work. All I get is
No component for supporting the service
BusinessObjects.Contracts.IThingey was found
Ultimately the class registration will be changed to another interface that the others inherit from, but one step at a time.
Any help figuring what's going on / what I'm doing wrong would be greatly appreciated.
You are not specifying any service that are registered by your classes, so by default the classes are registered as services to themselves. From the documentation:
By default the service of the component is the type itself
You must specify what services the component is registered against; you do that using the WithService property or shortcut functions (WithServiceBase(), WithServiceDefaultInterfaces(), etc). The linked resource contains the different selections methods you can use:
Base
DefaultInterfaces
FromInterface
AllInterfaces
Self
Select
Krzysztof Kozmic is recommending that you register your components using the Base service, which you would do like this:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IThingey>()
.WithServiceBase()
.LifestyleTransient()
);
we want to use Unity for IOC.
All i've seen is the implementation that there is one global static service (let's call it the the IOCService) which holds a reference to the Unity container, which registers all interface/class combinations and every class asks that object: give me an implementation for Ithis or IThat.
Frequently i see a response that this pattern is not good because it leads to a dependency from ALL classes to the IOCService (not to the Unity container because it is only known inside the IOCService).
But what i don't see often, is: what is the alternative way?
Michel
EDIT: found out that the global static service is called the service locator, added that to the title.
The alternative is to have a single instance of your container at the highest application level only, then use that container to resolve every object instance you need to create in that layer.
For example, the main method of most executables just looks like this (minus exception handling):
private static void main(string[] args) {
Container container = new Container();
// Configure the container - by hand or via file
IProgramLogic logic = container.Resolve<IProgramLogic>();
logic.Run();
}
Your program (represented here by the IProgramLogic instance) doesn't have to know anything about your container, because container.Resolve will create all its dependencies - and its dependencies' dependencies, on down to leaf classes with no dependencies of their own.
ASP.NET is a harder case, because web forms doesn't support constructor injection. I typically use Model-View-Presenter in my web forms applications, so my Page classes really only have one dependency each - on their presenter. I don't unit test them (everything interesting and testable is in my presenters, which I do test), and I don't ever substitute presenters. So I don't fight the framework - I just expose a container property on my HttpApplication class (in global.asax.cs) and use it directly from my Page files:
protected void Page_Load(object sender, EventArgs args) {
ICustomerPresenter presenter = Global.Container.Resolve<ICustomerPresenter>();
presenter.Load();
}
That's service locator of course - though the Page classes are the only thing coupled to the locator: your presenter and all of its dependencies are still fully decoupled from your IoC container implementation.
If you have a lot of dependencies in your Page files (that is, if you do not use Model-View-Presenter), or if it's important to you to decouple your Page classes from your Global application class, you should try to find a framework that integrates into the web forms request pipeline and use property injection (as suggested by Nicholas in the comments below) - or write your own IHttpModule and perform the property injection yourself.
+1 for knowing that Service Locator is a Bad Thing.
Problem is - Unity is not very sophisticated so I don't know how easy/hard is it to do IoC the right way with it.
I wrote few blogposts recently that you might find useful.
How I use IoC Containers
Pulling from the container
Instead of using the container explicitly, use it implicitly by leveraging constructor / property injection instead. Create a core class (or set of core classes) that depend on all the major pieces of your application.
Most containers will let you put ISomething[] in your constructor and it will inject all instances of ISomething into your class.
This way, when you bootstrap your application:
Instantiate your container
Register all your goodies
Resolve the core classes (this will pull in all the other dependencies you need)
Run the "main" part of the application
Now, depending on the type of application you are writing, there are different strategies for avoiding marking the IoC container as "static".
For ASP.NET web applications, you'll probably end up storing the container in the Application State. For ASP.NET MVC applications, you need to change out the Controller Factory.
For desktop applications, things get more complicated. Caliburn uses an interesting solution to this problem using the IResult construct (this is for WPF applications but could be adapted for Windows Forms as well.
In theory, to not have to worry about having a static IoC instance, you need to follow the Fight Club Rule - i.e. not to talk about the fight club - i.e. not to mention the IoC container.
This means that your components should largely be unaware about the IoC container. It should only be used at the topmost level when registering components. If a class needs to resolve something, it should really be injected as a dependency.
The trivial case is easy enough. If PaymentService depends on IAccount, the latter should be injected by IoC:
interface IAccount {
Deposit(int amount);
}
interface CreditCardAccount : IAccount {
void Deposit(int amount) {/*implementation*/}
int CheckBalance() {/*implementation*/}
}
class PaymentService {
IAccount account;
public PaymentService (IAccount account) {
this.account = account;
}
public void ProcessPayment() {
account.Deposit(5);
}
}
//Registration looks something like this
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();
The not so trivial case is where you want to inject multiple registrations. This especialy applies when you are doing any sort of Converntion Over Configuration and creating an object from a name.
For our payment example, say you want to enumerate through all accounts and check their balances:
class PaymentService {
IEnumerable<IAccount> accounts;
public PaymentService (IEnumerable<IAccount> accounts) {
this.accounts = accounts;
}
public void ProcessPayment() {
foreach(var account in accounts) {
account.Chackbalance();
}
}
}
Unity has the ability to register multiple interface to class mappings (they have to have different names thought). It does not, however, automatically inject those into classes that take collections of those registered interfaces. So, the above example will throw a resolution failed exception at runtime.
If you don't care that those objects live forever, you can register PaymentService in a more static fashion:
container.RegisterType<PaymentService>(new InjectionConstructor(container.ResolveAll<IAccount>()));
The above code will register PaymentService and will use a collection of IAccount instances that is resolved at registration time.
Alternatively, you can pass an instance of the container itself as a dependency and let PaymentService perform resolution of accounts. This is not quite following the Fight Club Rule, but is slightly less smelly than static Service Locator.
class PaymentService {
IEnumerable<IAccount> accounts;
public PaymentService (IUnityContainer container) {
this.accounts = container.ResolveAll<IAccount>();
}
public void ProcessPayment() {
foreach(var account in accounts) {
account.Chackbalance();
}
}
}
//Registration is pretty clean in this case
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();
container.RegisterInstance<IUnityContainer>(container);
If your concern is having a dependency on Unity throughout your application, you can combine the service locator with a facade to hide the IOC implementation. In this way, you do not create a dependency on Unity in your application, only on having something that can resolve types for you.
For example:
public interface IContainer
{
void Register<TAbstraction,TImplementation>();
void RegisterThis<T>(T instance);
T Get<T>();
}
public static class Container
{
static readonly IContainer container;
public static InitializeWith(IContainer containerImplementation)
{
container = containerImplementation;
}
public static void Register<TAbstraction, TImplementation>()
{
container.Register<TAbstraction, TImplementation>();
}
public static void RegisterThis<T>(T instance)
{
container.RegisterThis<T>(instance);
}
public static T Get<T>()
{
return container.Get<T>();
}
}
Now all you need is an IContainer implementation for your IOC container of choice.
public class UnityContainerImplementation : IContainer
{
IUnityContainer container;
public UnityContainerImplementation(IUnityContainer container)
{
this.container = container;
}
public void Register<TAbstraction, TImplementation>()
{
container.Register<TAbstraction, TImplementation>();
}
public void RegisterThis<T>(T instance)
{
container.RegisterInstance<T>(instance);
}
public T Get<T>()
{
return container.Resolve<T>();
}
}
Now you have a service locator that is a facade for IOC services, and can configure your service locator to use Unity or any other IOC container. The rest of the application has no dependency on the IOC implementation.
To configure your service locator:
IUnityContainer unityContainer = new UnityContainer();
UnityContainerImplementation containerImpl = new UnityContainerImplementation(unityContainer);
Container.InitializeWith(containerImpl);
For testing, you can create a stub of IContainer that returns whatever you want, and initialize Container with that.