Unity 2.0 and handling IDisposable types (especially with PerThreadLifetimeManager)

前端 未结 4 909
无人共我
无人共我 2020-12-02 16:50

I know that similar question was asked several times (for example: here, here,here and here) but it was for previous versions of Unity where the answer was dependent on used

相关标签:
4条回答
  • 2020-12-02 17:26

    I came across this issue recently myself as I was instrumenting Unity into my application. The solutions I found here on Stack Overflow and elsewhere online didn't seem to address the issue in a satisfactory way, in my opinion.

    When not using Unity, IDisposable instances have a well-understood usage pattern:

    1. Within a scope smaller than a function, put them in a using block to get disposal "for free".

    2. When created for an instance member of a class, implement IDisposable in the class and put clean-up in Dispose().

    3. When passed into a class's constructor, do nothing as the IDisposable instance is owned somewhere else.

    Unity confuses things because when dependency injection is done properly, case #2 above goes away. All dependencies should be injected, which means essentially no classes will have ownership of the IDisposable instances being created. However, neither does it provide a way to "get at" the IDisposables that were created during a Resolve() call, so it seems that using blocks can't be used. What option is left?

    My conclusion is that the Resolve() interface is essentially wrong. Returning only the requested type and leaking objects that need special handling like IDisposable can't be correct.

    In response, I wrote the IDisposableTrackingExtension extension for Unity, which tracks IDisposable instances created during a type resolution, and returns a disposable wrapper object containing an instance of the requested type and all of the IDisposable dependencies from the object graph.

    With this extension, type resolution looks like this (shown here using a factory, as your business classes should never take IUnityContainer as a dependency):

    public class SomeTypeFactory
    {
      // ... take IUnityContainer as a dependency and save it
    
      IDependencyDisposer< SomeType > Create()
      {
        return this.unity.ResolveForDisposal< SomeType >();
      }
    }
    
    public class BusinessClass
    {
      // ... take SomeTypeFactory as a dependency and save it
    
      public void AfunctionThatCreatesSomeTypeDynamically()
      {
        using ( var wrapper = this.someTypeFactory.Create() )
        {
          SomeType subject = wrapper.Subject;
          // ... do stuff
        }
      }
    }
    

    This reconciles IDisposable usage patterns #1 and #3 from above. Normal classes use dependency injection; they don't own injected IDisposables, so they don't dispose of them. Classes that perform type resolution (through factories) because they need dynamically created objects, those classes are the owners, and this extension provides the facility for managing disposal scopes.

    0 讨论(0)
  • 2020-12-02 17:33

    There are only a few circumstances where Unity will dispose an instance. It is really unsupported. My solution was a custom extension to achieve this - http://www.neovolve.com/2010/06/18/unity-extension-for-disposing-build-trees-on-teardown/

    0 讨论(0)
  • 2020-12-02 17:33

    would it be a viable solution to use the HttpContext.Current.ApplicationInstance.EndRequest event to hook to the end of the request and then disposing of the object stored in this lifetime manager? like so:

    public HttpContextLifetimeManager()
    {
        HttpContext.Current.ApplicationInstance.EndRequest += (sender, e) => {
            Dispose();
        };
    }
    
    public override void RemoveValue()
    {
        var value = GetValue();
        IDisposable disposableValue = value as IDisposable;
    
        if (disposableValue != null) {
            disposableValue.Dispose();
        }
        HttpContext.Current.Items.Remove(ItemName);
    }
    
    public void Dispose()
    {
        RemoveValue();
    }
    

    you don't have to use a child container like the other solution and the code used to dispose the objects is still in the lifetime manager like it should.

    0 讨论(0)
  • 2020-12-02 17:50

    Looking at the Unity 2.0 source code, it smells like the LifetimeManagers are used to keep objects in scope in different ways so the garbage collector doesn't get rid of them. For example, with the PerThreadLifetimeManager, it will use the ThreadStatic to hold a reference on each object with that particular thread's lifetime. However, it won't call Dispose until the container is Disposed.

    There is a LifetimeContainer object that is used to hold onto all the instances that are created, then is Disposed when the UnityContainer is Disposed (which, in turn, Disposes all the IDisposables in there in reverse chronological order).

    EDIT: upon closer inspection, the LifetimeContainer only contains LifetimeManagers (hence the name "Lifetime"Container). So when it is Disposed, it only disposes the lifetime managers. (and we face the problem that is discussed already).

    0 讨论(0)
提交回复
热议问题