How to reconcile IDisposable and IoC?

I finally wrap my head around IoC and DI in C # and I am struggling with some of the edges. I use a Unity container, but I think this question applies more widely.

Using an IoC container to issue instances that implement IDisposable freaks me out! How should you know if you should Dispose ()? Perhaps the instance was created just for you (and for this you must Dispose ()), or it may be an instance whose life is managed elsewhere (and for this you better not do this). Nothing in the code tells you, and in fact it can change depending on the configuration !!! It seems to me deadly.

Can any IoC experts describe good ways to deal with this ambiguity?

+41
c # inversion-of-control idisposable unity-container
Jun 12 '09 at 16:48
source share
7 answers

AutoFac handles this by allowing the creation of a nested container. When the container is finished, it automatically deletes all IDisposable objects inside it. More details here .

.. When enabling services, Autofac monitors one-time (IDisposable) components that are allowed. At the end of the unit of work, you delete the associated area of ​​life, and Autofac automatically cleans / removes the allowed services.

+7
Jun 12 '09 at 16:59
source share

You definitely don't want to call Dispose () on an object that has been injected into your class. You cannot assume that you are the only consumer. It is best to pack an unmanaged object into some sort of managed interface:

public class ManagedFileReader : IManagedFileReader { public string Read(string path) { using (StreamReader reader = File.OpenRead(path)) { return reader.ReadToEnd(); } } } 

This is just an example, I would use File.ReadAllText (path) if I were trying to read a text file in a line.

Another approach is to enter factory and manage the object yourself:

 public void DoSomething() { using (var resourceThatShouldBeDisposed = injectedFactory.CreateResource()) { // do something } } 
+17
Jun 18 '09 at 4:35
source share

This often puzzled me. Although I was not happy with this, I always came to the conclusion that it is better to never return an IDisposable to transition mode.

Recently, I have rephrased the question for myself: is this really an IoC problem or a problem with the .net framework? In any case, the disposal is awkward. It does not have a significant functional purpose, only a technical one. So this is more of a framework problem that we have to deal with than an IoC problem.

What I like about DI is that I can ask for a contract that provides me with functionality without worrying about the technical details. I am not the owner. There is no knowledge of in which layer it is absent. No knowledge of what technologies are needed to fulfill the contract, do not worry about life. My code looks beautiful and clean and can be checked. I can perform duties in the layers where they belong.

So, if there is an exception to this rule that requires me to organize a lifetime, let it be an exception. I love it or not. If an object that implements the interface requires me to dispose of it, I want to know about it since I started using this object as short as possible. The trick, resolving it with a child container, which will be installed some time later, may still make me keep the object alive longer than I should. The permissible lifetime of an object is determined upon registration of the object. Not according to the functionality that creates a child container and is held on it for a certain period of time.

So, while we developers have to worry about recycling (will this ever change?), I will try to introduce as few transient disposable objects as possible. 1. I am trying to make the object not IDisposable, for example, without saving disposable objects at the class level, but in a smaller area. 2. I am trying to make the object reusable so that I can use another lifetime manager.

If this is not possible, I use the factory to indicate that the user of the entered contract is the owner and should take responsibility for it.

There is one caveat: changing a contractor from unsafe to one-time will be a change. At this time, the interface will no longer be registered, but the interface to the factory. But I think this applies to another scenario. Forgetting to use a child container from now on will give memory problems. The factory approach will throw an IoC exception.

Code example:

 using System; using Microsoft.Practices.Unity; namespace Test { // Unity configuration public class ConfigurationExtension : UnityContainerExtension { protected override void Initialize() { // Container.RegisterType<IDataService, DataService>(); Use factory instead Container.RegisterType<IInjectionFactory<IDataService>, InjectionFactory<IDataService, DataService>>(); } } #region General utility layer public interface IInjectionFactory<out T> where T : class { T Create(); } public class InjectionFactory<T2, T1> : IInjectionFactory<T2> where T1 : T2 where T2 : class { private readonly IUnityContainer _iocContainer; public InjectionFactory(IUnityContainer iocContainer) { _iocContainer = iocContainer; } public T2 Create() { return _iocContainer.Resolve<T1>(); } } #endregion #region data layer public class DataService : IDataService, IDisposable { public object LoadData() { return "Test data"; } protected virtual void Dispose(bool disposing) { if (disposing) { /* Dispose stuff */ } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } #endregion #region domain layer public interface IDataService { object LoadData(); } public class DomainService { private readonly IInjectionFactory<IDataService> _dataServiceFactory; public DomainService(IInjectionFactory<IDataService> dataServiceFactory) { _dataServiceFactory = dataServiceFactory; } public object GetData() { var dataService = _dataServiceFactory.Create(); try { return dataService.LoadData(); } finally { var disposableDataService = dataService as IDisposable; if (disposableDataService != null) { disposableDataService.Dispose(); } } } } #endregion } 
+4
Mar 05 '15 at 13:49
source share

I think the overall best approach is simply not to get rid of something that has been introduced; you must assume that the injector performs the allocation and release.

+2
Jun 12 '09 at 16:52
source share

It depends on the structure of the DI. Some frameworks allow you to specify whether you want to use a shared instance (always using the same link) for each dependency entered. In this case, you most likely will not want to dispose.

If you can indicate that you want to enter a unique instance, you will want to get rid of (since it was specially created for you). However, I am not so familiar with Unity - you will need to check the docs on how to make this work there. This is part of the attribute with MEF and some others that I tried.

+2
Jun 12 '09 at 16:55
source share

Placing a facade in front of a container can also solve this problem. In addition, you can expand it to track a richer life cycle, such as service stops and startups or ServiceHost status transitions.

My container tends to live in IExtension, which implements the IServiceLocator interface. It is a facade of unity and provides easy access to WCF services. In addition, I have access to service events from ServiceHostBase.

As a result of the code that you finish, an attempt will be made to see if any one or one registered type of any of the interfaces that the facade monitors is registered.

It still does not allow you to manage it in a timely manner, since you are attached to these events, but it helps a little.

If you want to dispose in a timely manner (aka, now vs when the service is disabled). You need to know that the item you receive is disposable, it is part of the business logic to get rid of it, so IDisposable must be part of the object's interface. And, probably, there should be a check of the inactivity expectations associated with calling the dispose method.

+2
Mar 12
source share

Within Unity, there are two ways to register the entered classes: as single (you always get the same instance of the class when it is resolved), or you get a new instance of the class for each permission.

In a later case, you are responsible for deleting the authorized instance as soon as you do not need it (this is a perfectly reasonable approach). On the other hand, when you place a container (a class that handles object permissions), all single objects are also automatically deleted.

Therefore, there seems to be no problem with disposable disposable objects using the Unity infrastructure. I don’t know about other frameworks, but I believe that as long as the dependency injection infrastructure is strong enough, it will probably cope with this problem anyway.

+1
Sep 19 '09 at 20:28
source share



All Articles