Un Dbcontexte par requête en ASP.NET MVC (sans conteneur IOC))

veuillez vous excuser si vous avez déjà répondu à cette question, mais comment pouvez-vous garantir une entité DbContext par demande si vous n'utilisez pas un conteneur CIO? (Les réponses que j'ai trouvées jusqu'à présent portent sur les solutions de conteneurs IOC.)

il semble que la plupart des solutions s'accrochent dans le dictionnaire HttpContext.Current.Items , mais comment pouvez-vous garantir l'élimination du DbContext lorsque la demande est terminée? (Ou l'élimination n'est-elle pas absolument nécessaire avec un Fe DbContext ?)

Modifier

j'instancie et dispose actuellement mon DbContext dans Mes controllers, mais j'ai aussi plusieurs instanciations séparées de mon DbContext dans ActionFilters et mon MembershipProvider (et je viens de remarquer, aussi quelques validateurs). Donc, j'ai pensé que ce serait une bonne idée de centraliser l'instanciation et le stockage de mon DbContext pour réduire les frais généraux.

49
demandé sur devuxer 2011-06-13 22:29:36

6 réponses

j'utiliserais la méthode BeginRequest/EndRequest, ce qui permet de s'assurer que votre contexte est éliminé correctement lorsque la requête est terminée.

protected virtual void Application_BeginRequest()
{
    HttpContext.Current.Items["_EntityContext"] = new EntityContext();
}

protected virtual void Application_EndRequest()
{
    var entityContext = HttpContext.Current.Items["_EntityContext"] as EntityContext;
    if (entityContext != null)
        entityContext.Dispose();
}

et dans votre classe EntityContext...

public class EntityContext
{
    public static EntityContext Current
    {
        get { return HttpContext.Current.Items["_EntityContext"] as EntityContext; }
    }
}
58
répondu Chad Moran 2011-06-13 18:55:26

je sais que ce n'est pas une question récente, mais je vais poster ma réponse de toute façon, parce que je crois que quelqu'un pourrait trouver utile.

comme probablement beaucoup d'autres, j'ai suivi les étapes mentionnées dans la réponse acceptée. Youpi, ça marche. cependant , il y a une prise:

méthodes BeginRequest () et EndRequest () fire chaque fois qu'une demande est faite , mais pas seulement pour les pages aspx, mais pour tout le contenu statique! Que said, si vous utilisez le code mentionné ci-dessus et que vous avez sur votre page disons 30 images, vous ré-instanciez votre dbcontext 30 fois!

la solution pour cela est d'utiliser une classe d'enrubannage pour récupérer le contexte, quelque chose comme ceci:

internal static class ContextPerRequest
{
      internal static DB1Entities Current
      {
          get
          {
              if (!HttpContext.Current.Items.Contains("myContext"))
              {
                  HttpContext.Current.Items.Add("myContext", new DB1Entities());
              }
              return HttpContext.Current.Items["myContext"] as DB1Entities;
          }
      }
 }

et ensuite pour la disposition

protected void Application_EndRequest(object sender, EventArgs e)
{
   var entityContext = HttpContext.Current.Items["myContext"] as DB1Entities;
   if (entityContext != null) 
      entityContext.Dispose();
}

cette modification garantit que vous instanciez et éliminez votre contexte une seule fois par requête et seulement si nécessaire. Sélectionné réponse instancie contexte à chaque fois.

Note: DB1Entities est dérivé de DbContext (généré par VS). Vous voudriez probablement le modifier avec votre nom de contexte;)

Note 2: dans cet exemple, je travaille avec un seul dbcontext. Si vous devez travailler avec multiple, vous devrez modifier ce code en fonction de vos besoins. Ne prenez pas cela comme une solution ultime aux problèmes mondiaux., parce qu'il n'est certainement pas un produit final. Il vise simplement à donner un indice, comment il peut être réalisé d'une manière très facile.

Note 3: la même approche peut être utilisée dans différentes situations, par exemple lorsque vous souhaitez partager une instance de SqlConnection ou toute autre... Cette solution n'est pas exclusive à L'objet DbContext, ni à L'Entity framework.

70
répondu walther 2013-12-23 14:30:37

une façon serait de s'abonner à l'événement Application_BeginRequest , d'injecter le DbContext dans le HttpContext courant et dans le Application_EndRequest fetch du HttpContext et de disposer. Tout ce qui se trouve entre les deux (ce qui est à peu près tout :-)) pourrait récupérer le DbContext à partir du HttpContext courant et l'utiliser. Et, oui, vous devriez jeter. Et d'ailleurs, y a-t-il une raison pour que vous n'utilisiez pas un cadre DI qui le fait déjà pour vous entre autres choses utiles?

10
répondu Darin Dimitrov 2011-06-13 18:40:15

petite addition pour Chad Moran answer. Elle est inspirée des notes de walther. Pour éviter l'initialisation du contexte pour le contenu statique, nous devrions vérifier le gestionnaire de route actuel (cet exemple seulement pour MVC):

protected virtual void Application_BeginRequest()
{
  var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(this.Context));
  if (routeData != null && routeData.RouteHandler is MvcRouteHandler)
  {
    HttpContext.Current.Items["_EntityContext"] = new EntityContext();
  }
}
7
répondu DrunkCoder 2013-03-26 21:06:34

si vous implémentez IDisposable dans votre controller, et disposez le contexte dans la méthode de disposition, et instanciez le nouveau contexte dans le controller constructor, vous devez être en sécurité car le controller est instancié pour chaque requête. Je ne vois pas, cependant, pourquoi voudriez-vous faire cela? ... Vous devriez utiliser DI, ou faire une usine de contexte avec une instance statique de contexte. Si vous n'utilisez pas une instance (vous en faites une pour chaque requête), vous allez avoir des problèmes à un moment donné. Le problème avec undisposed contexte est que EF cache des données dans le contexte, et si une autre instance de contexte change quelque chose dans DB qui est déjà caché dans un autre contexte - vous avez État inconsistant. Avant que DI ne devienne si populaire, j'avais l'habitude d'avoir une instance statique de contexte quelque part dans l'application, et c'est beaucoup plus rapide et plus sûr que d'avoir chaque requête faire son propre contexte, mais vous devez mettre en œuvre le code de vérification d'état qui fait que la connexion de contexte à db est ok... Il y a de bien meilleures solutions pour ce problème, et le meilleur est d'utiliser un certain cadre DI. Je recommande Ninject en combinaison avec MVCTurbine, il est facile à mettre en place et vous pouvez l'ajouter par NuGet.

1
répondu Goran Obradovic 2011-06-13 18:49:57

la pente glissante ici a un état incohérent. Si vous êtes app va avoir plusieurs utilisateurs sur elle, et ils ont le potentiel de changer les données en même temps, alors vous pourriez commencer à courir dans des problèmes avec l'intégrité des données si vous gardez un contexte unique.

0
répondu mymex1 2011-06-14 15:43:39