#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 они есть.