Подтвердить что ты не робот

Один DbContext для каждого запроса в ASP.NET MVC (без контейнера МОК)

Извините, если об этом уже ответили, но как вы гарантируете один Entity Framework DbContext для каждого запроса, если вы не используете контейнер IOC? (Ответы, которые я встречал до сих пор, касаются решений контейнеров IOC.)

Кажется, что большинство решений подключаются к словарю HttpContext.Current.Items, но как вы гарантируете удаление DbContext, когда запрос завершен? (Или удаление не обязательно необходимо с помощью EF DbContext?)

Edit

В настоящее время я создаю экземпляр и удаляю свой DbContext в своих контроллерах, но у меня также есть несколько отдельных экземпляров моего DbContext в ActionFilters и моем MembershipProvider (и я только что заметил, также пару валидаторов). Итак, я подумал, что было бы неплохо централизовать создание экземпляров и хранение моего DbContext, чтобы уменьшить накладные расходы.

4b9b3361

Ответ 1

Я бы использовал метод BeginRequest/EndRequest, это поможет убедиться, что ваш контекст правильно утилизирован, когда запрос завершен.

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

И в вашем классе EntityContext...

public class EntityContext
{
    public static EntityContext Current
    {
        get { return HttpContext.Current.Items["_EntityContext"] as EntityContext; }
    }
}

Ответ 2

Я знаю, что это не недавний вопрос, но я все равно отправлю свой ответ, потому что считаю, что кто-то может найти его полезным.

Как и многие другие, я следовал шагам, указанным в принятом ответе. Да, это работает. ОДНАКО, там один catch:

Способы BeginRequest() и EndRequest() срабатывают каждый раз, когда запрос выполняется, но не только для страниц aspx, но и для ВСЕГО СТАТИЧЕСКОГО СОДЕРЖАНИЯ! Тем не менее, если вы используете код, упомянутый выше, и у вас на вашей странице есть 30 изображений, вы повторно создаете свой dbcontext 30 раз!

Решением для этого является использование класса-оболочки для извлечения контекста, что-то вроде этого:

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

И затем для утилизации

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

Эта модификация гарантирует, что вы создаете экземпляр и удаляете свой контекст только один раз для каждого запроса и только при необходимости. Выбранный ответ создает контекст каждый раз.

Примечание. DB1Entities выводится из DbContext (генерируется VS). Вероятно, вы захотите изменить его с помощью своего контекстного имени;)

Примечание 2: в этом примере. Я работаю только с одним dbcontext. Если вам нужно работать с несколькими, вам нужно будет изменить этот код в соответствии с вашими потребностями. Не считайте это окончательным решением мировых проблем, потому что это, конечно, не конечный продукт. Это означает просто дать подсказку, как это может быть достигнуто очень простым способом.

Примечание 3: Тот же подход может использоваться и в разных ситуациях, например, если вы хотите поделиться экземпляром SqlConnection или любым другим... Это решение не является эксклюзивным для DbContext, а также в инфраструктуру Entity.

Ответ 3

Один из способов - подписаться на событие Application_BeginRequest, вставить DbContext в текущий HttpContext и в выборку Application_EndRequest из HttpContext и удалить. Все, что находится между ними (это почти все:-)), может извлечь DbContext из текущего HttpContext и использовать его. И, да, вы должны распоряжаться им. И, кстати, есть ли какая-то причина, по которой вы не используете рамки DI, которые уже делают это для вас среди других полезных вещей?

Ответ 4

Небольшое дополнение для ответа Чада Морана. Это вдохновлено примечаниями Вальтера. Чтобы избежать инициализации контекста для статического содержимого, мы должны проверить текущий обработчик маршрута (этот пример только для 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();
  }
}

Ответ 5

Если вы реализуете IDisposable в своем контроллере и удаляете контекст в методе утилизации и создаете новый контекст в конструкторе контроллера, вы должны быть в безопасности, поскольку контроллер создается для каждого запроса. Однако я не вижу, почему вы хотите это сделать? ... Вы должны использовать DI или создать контекст factory с одним статическим экземпляром контекста. Если вы не используете один экземпляр (вы делаете по одному для каждого запроса), вы должны иметь проблемы в какой-то момент. Проблема с неразделенным контекстом заключается в том, что EF кэширует данные в контексте, и если какой-либо другой экземпляр контекста что-то изменяет в базе данных, которая уже кэшируется в другом контексте - у вас есть несогласованное состояние. До того, как DI стал настолько популярным, у меня был один статический экземпляр контекста где-то в приложении, и это намного быстрее и безопаснее, чем каждый запрос создает свой собственный контекст, но вам нужно реализовать код проверки состояния, который гарантирует, что этот контекст подключение к db в порядке... Есть много лучших решений этой проблемы, и лучше всего использовать некоторые рамки DI. Я бы порекомендовал Ninject в сочетании с MVCTurbine, его легко настроить, и вы можете добавить его через NuGet.

Ответ 6

Скользкий уклон здесь имеет несогласованное состояние. Если у вас есть приложение, у вас будет несколько пользователей, и у них есть потенциал для одновременного изменения данных, тогда вы можете столкнуться с проблемами с целостностью данных, если вы сохраняете один контекст.