Utilisation DbContext à l'ASP .Net Singleton Injecté Classe
Je besoin pour accéder à ma base de données dans une classe Singleton instancié dans mon Démarrage de la classe. Il semble que l'injecter directement les résultats dans un DbContext qui est éliminé.
J'obtiens l'erreur suivante:
Ne peut pas accéder à un objet supprimé. Nom de l'objet: 'MyDbContext'.
Ma question est double: Pourquoi ne pas ce travail et comment puis-je accéder à ma base de données dans une instance de la classe singleton?
Voici mon ConfigureServices méthode dans mon Démarrage de classe:
public void ConfigureServices(IServiceCollection services)
{
//code removed for brevity
services.AddEntityFramework().AddSqlServer().AddDbContext<MyDbContext>(
options =>
{
var config = Configuration["Data:DefaultConnection:ConnectionString"];
options.UseSqlServer(config);
});
//code removed for brevity
services.AddSingleton<FunClass>();
}
Voici ma classe de contrôleur:
public class TestController : Controller
{
private FunClass _fun;
public TestController(FunClass fun)
{
_fun = fun;
}
public List<string> Index()
{
return _fun.GetUsers();
}
}
Voici mon FunClass:
public class FunClass
{
private MyDbContext db;
public FunClass(MyDbContext ctx) {
db = ctx;
}
public List<string> GetUsers()
{
var lst = db.Users.Select(c=>c.UserName).ToList();
return lst;
}
}
- Voir cette réponse. Un objet ne peut pas avoir de dépendances avec une durée de vie plus courte que lui-même. Vous pouvez injecter une usine à créer à durée de vie courte des cas, ou de refactoriser donc la racine de l'objet graphique n'est pas un singleton.
- Je déconseille vivement de vous inscrire à votre
DbContext
comme un Singleton, il existe de nombreux articles sur le web que vous dire pourquoi c'est une mauvaise idée. Voici un répondre fourni par le créateur de Simple Injecteur qui tente d'expliquer pourquoi. Je suggère fortement d'utiliser un modèle comme le Référentiel ou l'Unité de modèles de Travail. - merci. J'ai noté un avertissement dans mon travail de réponse.
- Double Possible de Entity Framework Core service de durée de vie par défaut
Vous devez vous connecter pour publier un commentaire.
La raison pour laquelle il n'a pas de travail est parce que le
.AddDbContext
extension est l'ajoutant dont la portée est déterminée par la demande. Portée par la demande est généralement ce que vous voulez et, généralement, d'enregistrer les modifications serait appelée une fois par demande et puis ledbcontext
seraient éliminés à la fin de la requête.Si vous avez vraiment besoin d'utiliser un
dbContext
à l'intérieur d'unsingleton
, alors votreFunClass
classe devrait probablement prendre une dépendance surIServiceProvider
etDbContextOptions
au lieu de directement prendre une dépendance sur leDbContext
, de cette façon, vous pouvez créer vous-même.Cela dit, mon conseil serait de vous demander si vous avez vraiment besoin de votre FunClass être un singleton, je voudrais éviter sauf si vous avez une très bonne raison pour en faire un singleton.
IServiceProvider
est un anti-modèle, car elle lie vos types dans un conteneur spécifique (IServiceProvider
dans ce cas) et doivent être évités. on doit utiliser soit la méthode de fabrique ou de l'usine de classe/interface pour le mettre en œuvre. la méthode peut être mise en œuvre aimé commeservices.AddSingleton<FunClass>( services => new FunClass(new GMBaseContext));
. Si vous avez besoin des services d'application, vous pouvez les résoudre au sein de l'usine méthode viaservices.RequestService<SomeOtherDependency>()
et passer au constructeur deGMBaseContext
.DbContextOptions
est égalementScoped
et ne peut pas être résolu pour objet singletonMise à jour
Je suis pleinement conscient que cette solution n'est pas la bonne façon de le faire. Merci de ne pas faire ce que j'ai fait ici toutes ces années. En fait, ne pas injecter un singleton DbContext à tous.
Vieille réponse
La solution a été d'appeler AddSingleton avec ma classe instanciée dans le paramètre de méthode dans mon Démarrage de classe:
La solution a été de changer ma classe DbContext:
Que plusieurs personnes ont cependant prévenu, à l'aide d'un DbContext dans une classe singleton peut être une très mauvaise idée. Mon utilisation est très limitée dans le code réel (pas l'exemple FunClass), mais je pense que si vous faites cela, il serait mieux de trouver d'autres moyens.
Comme mentionné au début
.AddDbContext
extension est l'ajoutant dont la portée est déterminée par la demande. Donc DI ne peut pas instancierScoped
objet à construireSingleton
un.Vous devez créer et de disposer d'instance de
MyDbContext
par vous-même, c'est encore mieux, car DbContext doivent être éliminés après l'aide le plus tôt possible. Pour passer de la chaîne de connexion, vous pouvez prendreConfiguration
deStartup
classe:Dans
Startup.cs
configurerDbContextOptionBuilder
et enregistrer votre singleton:C'est un peu sale, mais fonctionne très bien.
Pas besoin de surcharger ctor de MyDbContext.