web-dev-qa-db-fra.com

Quand les instances injectées par dépendance .NET Core sont-elles supprimées?

ASP.NET Core utilise des méthodes d'extension sur IServiceCollection pour configurer l'injection de dépendance, puis lorsqu'un type est nécessaire, il utilise la méthode appropriée pour créer une nouvelle instance:

  • AddTransient<T> - ajoute un type qui est recréé chaque fois qu'il est demandé.
  • AddScoped<T> - ajoute un type qui est conservé pour l'étendue de la demande.
  • AddSingleton<T> - ajoute un type lors de sa première demande et le conserve.

J'ai des types qui implémentent IDisposable et qui causeront des problèmes s'ils ne sont pas supprimés - dans chacun de ces modèles quand Dispose est-il réellement appelé?

Y a-t-il quelque chose que je dois ajouter (comme la gestion des exceptions) pour garantir que l'instance est toujours supprimée?

34
Keith

Les objets résolus ont le même cycle de durée de vie/suppression que leur conteneur, sauf si vous supprimez manuellement les services transitoires dans le code à l'aide de l'instruction using ou de la méthode .Dispose().

Dans ASP.NET Core, vous obtenez un conteneur de portée qui est instancié par demande et supprimé à la fin de la demande. À l'heure actuelle, les dépendances étendues et transitoires créées par ce conteneur seront également supprimées (c'est-à-dire si elles implémentent l'interface IDisposable), que vous pouvez également voir sur le code source ici .

public void Dispose()
{
    lock (ResolvedServices)
    {
        if (_disposeCalled)
        {
            return;
        }
        _disposeCalled = true;
        if (_transientDisposables != null)
        {
            foreach (var disposable in _transientDisposables)
            {
                disposable.Dispose();
            }

            _transientDisposables.Clear();
        }

        // PERF: We've enumerating the dictionary so that we don't allocate to enumerate.
        // .Values allocates a ValueCollection on the heap, enumerating the dictionary allocates
        // a struct enumerator
        foreach (var entry in ResolvedServices)
        {
            (entry.Value as IDisposable)?.Dispose();
        }

        ResolvedServices.Clear();
    }
}

Les singletons sont éliminés lorsque le conteneur parent est éliminé, ce qui signifie généralement lorsque l'application s'arrête.

TL; DR : Tant que vous n'instanciez pas les services étendus/transitoires au démarrage de l'application (en utilisant app.ApplicationServices.GetService<T>()) et vos services implémenter correctement l'interface jetable (comme pointé dans MSDN ) il n'y a rien dont vous devez vous occuper.

Le conteneur parent n'est pas disponible en dehors de la méthode Configure(IApplicationBuilder app) sauf si vous faites des choses amusantes pour le rendre accessible à l'extérieur (ce que vous ne devriez pas de toute façon).

Bien sûr, il est encouragé à libérer les services transitoires dès que possible, surtout s'ils consomment beaucoup de ressources.

38
Tseng