40 votes

Unity 2.0 et gestion des types IDisposable (en particulier avec PerThreadLifetimeManager)

Je sais que la même question a été posée à plusieurs reprises (par exemple: ici, ici,ici et ici), mais c'était pour les versions précédentes de l'Unité où la réponse était à la charge sur LifetimeManager classe.

La Documentation dit:

L'unité utilise des types spécifiques qui héritent à partir de la LifetimeManager de la classe de base (collectivement, la durée de vie les gestionnaires) pour contrôler la façon dont il stocke les références à des instances d'objet et comment le conteneur dispose de ces les instances.

Ok, ça sonne bien donc j'ai décidé de vérifier la mise en œuvre de la construire dans la durée de vie des gestionnaires. Ma conclusion:

  • TransientLifetimeManager - pas de manipulation de l'élimination. Conteneur ne résout instance et il n'a pas le suivre. Code appelant est responsable de l'élimination de l'instance.
  • ContainerControlledLifetimeManager - dispose d'instance lorsque la durée de vie du gestionnaire est éliminé (= lorsque le récipient est disposé). Fournit de l'instance du singleton partagée entre tous les conteneurs dans hiérarchique.
  • HierarchicalLifetimeManager - dérive de comportement d' ContainerControlledLifetimeManager. Il fournit un "singleton" instance par conteneur dans hiérarchique (sous-conteneurs).
  • ExternallyControlledLifetimeManager - pas de manipulation de l'élimination. Comportement Correct parce que le conteneur n'est pas propriétaire de l'instance.
  • PerResolveLifetimeManager - pas de manipulation de l'élimination. Il est généralement la même que TransientLifetimeManager , mais il permet la réutilisation de l'instance pour l'injection de dépendances lors de la résolution d'ensemble de l'objet graphique.
  • PerThreadLifetimeManager - pas de manipulation de disposer comme il est également décrite dans MSDN. Qui est responsable de l'élimination?

La mise en œuvre de build- PerThreadLifetimeManager est:

public class PerThreadLifetimeManager : LifetimeManager
{
    private readonly Guid key = Guid.NewGuid();
    [ThreadStatic]
    private static Dictionary<Guid, object> values;

    private static void EnsureValues()
    {
        if (values == null)
        {
            values = new Dictionary<Guid, object>();
        }
    }

    public override object GetValue()
    {
        object result;
        EnsureValues();
        values.TryGetValue(this.key, out result);
        return result;
    }

    public override void RemoveValue()
    { }

    public override void SetValue(object newValue)
    {
        EnsureValues();
        values[this.key] = newValue;
    }
}

Donc conteneur d'élimination ne pas jeter jetables instances créées avec cette vie de gestionnaire. Fil d'achèvement permettra également de ne pas disposer de ces instances. Alors, qui est chargé de libérer les instances?

J'ai essayé manuellement éliminer résolu exemple dans le code et j'ai trouvé un autre problème. Je ne peux pas le démontage de la instnace. RemoveValue de la durée de vie de manager est vide - une fois que l'instance est créée, il n'est pas possible de le supprimer à partir du fil de dictionnaire statique (je suis aussi méfiant qu' TearDown méthode ne fait rien). Donc, si vous appelez Resolve après l'élimination de l'instance, vous obtiendrez éliminés de l'instance. Je pense que cela peut être assez gros problème lors de l'utilisation de cette vie avec le gestionnaire de threads du pool de threads.

Comment utiliser correctement cette vie manager?

En outre, cette mise en œuvre est souvent réutilisé dans la coutume durée de vie des gestionnaires comme PerCallContext, PerHttpRequest, PerAspNetSession, PerWcfCall, etc. Seul thread dictionnaire statique est remplacé avec quelques autres construire.

Aussi dois-je comprends bien que la manipulation jetables objets dépend de la durée de vie de gestionnaire? Ainsi, le code de l'application est dépendante de la durée de vie utilisé manager.

J'ai lu que dans d'autres conteneurs IoC traitant temporaire jetable objets est gérée par les sous-conteneurs, mais je n'ai pas trouver d'exemple de l'Unité - il pourrait être probablement manipulés avec local étendue de sous-conteneur et HiearchicalLifetimeManager mais je ne suis pas sûr de savoir comment faire.

6voto

Rory Primrose Points 530

Unity ne disposera d’une instance que dans quelques rares cas. C'est vraiment non supporté. Ma solution était une extension personnalisée permettant d'y parvenir - http://www.neovolve.com/post/2010/06/18/Unity-Extension-For-Disposing-Build-Trees-On-TearDown.aspx

2voto

Garo Yeriazarian Points 2189

La recherche à l'Unité 2.0 code source, ça sent le LifetimeManagers sont utilisés pour garder les objets dans le champ d'application de différentes manières, de sorte que le garbage collector ne pas se débarrasser d'eux. Par exemple, avec la PerThreadLifetimeManager, il va utiliser la ThreadStatic de tenir une référence sur chaque objet avec le fil de sa vie. Cependant, il ne fera pas appel de Disposer jusqu'à ce que le conteneur est Éliminé.

Il y a un LifetimeContainer objet qui est utilisé pour conserver toutes les instances qui sont créés, puis sont Éliminés lors de la UnityContainer est Éliminé (qui, à son tour, Dispose de tous les IDisposables là, dans l'ordre chronologique inverse).

EDIT: en regardant de plus près, la LifetimeContainer ne contient LifetimeManagers (d'où le nom de "durée de Vie"Conteneur). Donc, quand il est Éliminé, il ne dispose que de la durée de vie des gestionnaires. (et nous sommes confrontés au problème qui est déjà discuté).

1voto

Francois Joly Points 177

Serait-il une solution viable d’utiliser l’événement HttpContext.Current.ApplicationInstance.EndRequest pour s’accrocher à la fin de la demande et ensuite disposer de l’objet stocké dans ce gestionnaire de durée de vie? ainsi:

 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();
}
 

vous n'avez pas besoin d'utiliser un conteneur enfant comme l'autre solution et le code utilisé pour supprimer les objets est toujours dans le gestionnaire de durée de vie, comme il se doit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X