Il existe des différences importantes entre l'Étendue et Singleton services. L'avertissement est là pour apporter ce à la lumière, et de l'éteindre ou de commutation autour de la durée de vie sans distinction à faire disparaître, ne résoudra pas le problème.
Services spécifiques sont créés à partir d'un IServiceScope
. L'un de ses objectifs majeurs est d'assurer que tout IDisposable
services qui sont créés dans le champ d'application soient éliminés correctement quand le champ est lui-même.
Dans ASP.NET de Base, un service de champ est automatiquement créé pour vous sur chaque demande entrante, de sorte que d'ordinaire, vous n'avez pas besoin de vous inquiéter à ce sujet. Cependant, vous pouvez également créer votre propre champ d'application du service, vous avez juste besoin de disposer de vous-même.
Une façon de le faire est:
- faites votre singleton service
IDisposable
,
- injecter
IServiceProvider
,
- créer et enregistrer un
IServiceScope
de la portée à l'aide de l' IServiceProvider.CreateScope()
méthode d'extension,
- utilisez ce champ pour créer la portée du service dont vous avez besoin,
- disposer le champ d'application du service de l'
Dispose
méthode.
services.AddSingleton<IActiveUsersService, ActiveUsersService>();
services.AddScoped<IMongoDbContext, MongoDbContext>();
services.AddSingleton(option =>
{
var client = new MongoClient(MongoConnectionString.Settings);
return client.GetDatabase(MongoConnectionString.Database);
})
public class MongoDbContext : IMongoDbContext
{
private readonly IMongoDatabase _database;
public MongoDbContext(IMongoDatabase database)
{
_database = database;
}
public IMongoCollection<T> GetCollection<T>() where T : Entity, new()
{
return _database.GetCollection<T>(new T().CollectionName);
}
}
public class ActiveUsersService: IActiveUsersService, IDisposable
{
private readonly IServiceScope _scope;
public ActiveUsersService(IServiceProvider services)
{
_scope = services.CreateScope(); // CreateScope is in Microsoft.Extensions.DependencyInjection
}
public IEnumerable<Foo> GetFooData()
{
using (var context = _scope.ServiceProvider.GetRequiredService<IMongoDbContext>())
{
return context.GetCollection<Foo>();
}
}
public void Dispose()
{
_scope?.Dispose();
}
}
Selon la façon dont vous utilisez ces et l'étendue des services que vous consommez, vous pouvez effectuer l'une des opérations suivantes:
- créer une instance unique de l'étendue du service et de l'utiliser pour la vie de l'singleton; ou
- stocker une référence à l' (injectée) racine
IServiceProvider
, l'utiliser pour créer un nouveau IServiceScope
à l'intérieur d'un using
bloc à chaque fois que vous besoin d'une étendue de services, et de laisser le champ d'application sont disposées lorsque le bloc de sorties.
Il suffit de garder à l'esprit que tout IDisposable
services créés à partir d'un IServiceScope
sera automatiquement éliminé lorsque l'étendue elle-même n'.
En bref, ne vous contentez pas de changement autour de la durée de vie de vos services à "faire fonctionner"; vous devez toujours penser à propos de ceux-ci et être sûr qu'ils éliminés correctement. ASP.NET Noyau gère les cas les plus courants automatiquement; pour les autres, vous avez juste besoin de faire un peu plus de travail.
Depuis C# 1.0, nous avons eu using()
blocs pour s'assurer que les ressources sont éliminés correctement. Mais using()
blocs ne fonctionne pas lorsque quelque chose d'autre (la DI de service) est de la création de ces ressources pour vous. C'est là où l'Étendue des services et de les utiliser de manière incorrecte entraînera les ressources des fuites dans votre programme.