Удаление ObjectContext (по запросу) после использования

#c# #asp.net-mvc #entity-framework #inversion-of-control

#c# #asp.net-mvc #entity-framework #инверсия управления

Вопрос:

Я использую концепцию создания одного ObjectContext для каждого запроса. Технически, я добавляю экземпляр ObjectContext в HttpContext.Current.Товары. Но я не знаю, как правильно уничтожить этот экземпляр. Безопасно ли использовать HttpModule и удалять ObjectContext внутри? Я имею в виду, HttpModule может вызываться для любого вида запроса. Я не хочу использовать DI / IoC matters, потому что проект должен быть облегченным (не допускаются сторонние библиотеки).

ОБНОВЛЕНИЕ: вот простой код: Создан ObjectContext для каждого запроса (класс сущностей)

 public static class ObjectContextPerRequest
{
    public const string ObjectKey = "_per_request_context_key";

    public static Entities PerRequest
    {
        get
        {
            if (HttpContext.Current.Items[ObjectKey] != null)
            {
                var eContext = new Entities();
                HttpContext.Current.Items.Add(ObjectKey, eContext);

                return eContext;
            }

            return HttpContext.Current.Items[ObjectKey] as Entities;
        }
    }
}
  

и модуль удаления:

 class ObjectContextManagerModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.EndRequest  = (s, e) => { Dispose(); };
    }

    public void Dispose()
    {
        if (HttpContext.Current.Items[ObjectContextPerRequest.ObjectKey] != null)
        {
            var edmx = (ObjectContext)HttpContext.Current.Items[ObjectContextPerRequest.ObjectKey];
            edmx.Dispose();
            edmx = null;
        }
    }
}
  

Комментарии:

1. Куда вы вызываете SaveChanges() ? И как вы предотвращаете его вызов при возникновении исключения?

2. Я использую его в репозиториях. Он может использоваться в нескольких местах (например, контроллер / представления). Мне нужно централизовать удаление ObjectContext только после завершения всех вызовов (например, OnResponseEnd). Обработка исключений реализована на уровне уровня данных.

3. @Orif Lightweight не имеет ничего общего со сторонними библиотеками. Это странное требование, учитывая, что существует множество отличных облегченных альтернатив тому, что включено в .net framework.

4. @jfar на самом деле, мой босс требует, чтобы проект был более чистым.

5. @Orif Ваш босс идиот, но вы, вероятно, уже знакомы с этим. Выбираем Unity просто потому, что это контейнер IoC, который мы используем; он написан и протестирован Microsoft и предоставляет LifetimeManager именно для того, чего вы пытаетесь достичь здесь. Спросите своего босса, действительно ли они думают, что могут написать лучший код, чем MS.

Ответ №1:

Будет безопаснее создать контекст во время BeginRequest, а затем удалить его во время EndRequest или ReleaseRequestState (вероятно, EndRequest). Init — это когда модуль запущен, Dispose — это когда сам модуль удален, а модули не создаются и удаляются при каждом запросе.

* ОБНОВЛЕНИЕ для комментариев *

Модуль должен использовать свой метод Init для присоединения к событиям приложения, например:

 public void Init(HttpApplication app)
{
   app.BeginRequest  = new EventHandler(OnBeginRequest);
   app.EndRequest  = new EventHandler(OnEndRequest);
}
  

Обратите внимание, что доступны и другие синтаксисы, но это тот, который задокументирован в MSDN.

Это будет срабатывать при каждом запросе, который попадает в ваше приложение. Таким образом, если ваша настройка IIS направляет статические запросы к файлам (например, изображениям и CSS-файлам) через приложение (что верно для IIS 7 в режиме интегрированного конвейера), то ваши обработчики событий должны учитывать это, не создавая экземпляр ObjectContext в случаях, когда он вам не нужен.

* ОБНОВЛЕНИЕ для MVC *

Поскольку вы используете приложение MVC, вы также могли бы рассмотреть возможность выполнения этого в базовом классе контроллера или в actionfilter, используя вызовы OnActionExecuting и OnActionExecuted.

В качестве ActionFilter вы можете убедиться, что применяете его только к контроллерам, которым нужен контекст данных.

Комментарии:

1. @Paul, ты имеешь в виду события Application_BeginRequest / Application_EndRequest в Global.asax? Если это так, эти события запускаются при каждом запросе (например, image / css / *.* независимо от того, что запрашивается у клиента). Инициализация / удаление в этих событиях вызовет головную боль.

2. Является ли ваше приложение приложением Web Forms или приложением MVC?

3. Базовый класс контроллера — плохая идея, потому что у вас могут быть дочерние действия на разных контроллерах в рамках одного запроса. В противном случае 1.

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

5. @Paul — Потому что базовые контроллеры или что-либо еще, что угодно, тесно связано со всеми его производными типами. Вы хотите сохранить любое «базовое» что-либо как можно более простым. Всегда лучше использовать альтернативы для реализации ортогональных задач, если они доступны, а в MVc они есть.