Управление областями действия AutoFac для каждого сеанса и запроса в asp.net mvc 3
Я хочу использовать AutoFac в веб-приложении. У меня есть корневой контейнер, дочерний контейнер для сеанса и дочерний контейнер для запроса. Я пытаюсь выяснить, как лучше всего управлять этими областями жизни. В Global.asax.cs я добавил следующее:
protected void Application_Start(object sender, EventArgs e)
{
var container = ...;
}
protected void Session_Start(object sender, EventArgs e)
{
var sessionScope = container.BeginLifetimeScope("session");
Session["Autofac_LifetimeScope"] = sessionScope;
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
var sessionScope = (ILifetimeScope) Session["Autofac_LifetimeScope"];
var requestScope = sessionScope.BeginLifetimeScope("httpRequest");
HttpContext.Current.Items["Autofac_LifetimeScope"] = requestScope;
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var requestScope = (ILifetimeScope)HttpContext.Current.Items["Autofac_LifetimeScope"];
requestScope.Dispose();
}
protected void Session_End(object sender, EventArgs e)
{
var sessionScope = (ILifetimeScope)Session["Autofac_LifetimeScope"];
sessionScope.Dispose();
}
protected void Application_End(object sender, EventArgs e)
{
container.Dispose();
}
Как я могу сказать AutoFac использовать мой requestScope в качестве отправной точки для получения зависимостей, чтобы реализации, которые я регистрирую как InstancePerLifetimeScope, были разрешены с использованием моей requestScope?
Если это невозможно, могу ли я заставить AutoFac создать свою область действия для каждого запроса из моего sessionScope?
Или я не на том пути? Может ли быть другой способ заставить AutoFac знать об этой иерархии?
Любая помощь или другие комментарии приветствуются.
В ответ на Стивена.
Я все еще на ранних стадиях прототипирования, но возможные вещи, которые вы могли бы иметь в sessionScope:
- Пользовательские настройки
- Контекст аутентификации и авторизации (например, идентификация пользователя и роли)
Не относящийся к приложению, которое я собираюсь создать, но в среде электронной коммерции корзина покупок может быть ограничена сессией. Это, наверное, лучший конкретный пример. Это то, что вы ожидаете, чтобы жить дольше, чем запрос, но короче, чем приложение.
Может быть и больше, но если у меня есть стратегия для UserPreferences, Authentication и Authorization, то эта стратегия также может быть применена к другим компонентам, которые будут созданы позже.
Возможная альтернатива - получить всю необходимую информацию в начале запроса и поместить эти настроенные компоненты в область запроса. Он даст мне ожидаемый результат, но он не соответствует модели, которую я имею в виду в отношении иерархии приложений-> сеансов-> запросов. Я надеюсь создать систему, которая имеет смысл, так как я определенно не та, которая будет поддерживать ее.
1 ответ
Что вам нужно сделать, это реализовать свой собственный Autofac.Integration.Mvc.ILifetimeScopeProvider
, Этот интерфейс определяет, как / где генерируются области времени жизни запроса. По умолчанию, Autofac.Integration.Mvc.RequestLifetimeScopeProvider
обрабатывает создание, утилизацию и обслуживание жизненных областей на основе запроса.
Вы можете просмотреть код для RequestLifetimeScopeProvider
здесь, что я настоятельно рекомендую сделать, если вы планируете предпринять это. Это лучший пример, который я могу придумать, содержащий рабочий код, показывающий ответственность за одну из этих вещей.
Ваша реализация ILifetimeScopeProvider
будет там, где вы захватите дочерний контейнер сеанса, создадите из него контейнер запроса и, в конце запроса, очистите контейнер запроса. Вы также можете создать там сессионный контейнер, если он не существует. Обработка очистки / удаления контейнера сеанса может быть сложной, но с точки зрения дизайна было бы неплохо, если бы все было в одном месте, а не в поставщике, некоторые в вашем классе приложения.
Как только у вас есть ILifetimeScopeProvider
вы будете использовать его при настройке вашего средства разрешения зависимостей.
var scopeProvider = new MyCustomLifetimeScopeProvider(container, configAction);
var resolver = new AutofacDependencyResolver(container, scopeProvider);
DependencyResolver.SetResolver(resolver);
Несколько слов предупреждения о понятии области действия сеанса:
- Ваш след памяти может быть огромным. В итоге вы получите пожизненную область действия для каждого пользователя в вашей системе. Несмотря на то, что время жизни запроса всплывает и уходит довольно быстро, эти области действия на уровне сеанса потенциально могут существовать долго. Если у вас много элементов сессий, у вас будет достаточно памяти для каждого пользователя. Если люди "откажутся" от своих сессий без надлежащего выхода из системы, это все дольше будет жить.
- Прижизненные области действия и их содержимое не сериализуются. Глядя на код для LifetimeScope, он не помечен
[Serializable]
... и даже если бы это было так, разрешенные объекты, живущие там, не обязательно все помечены как сериализуемые. Это важно, потому что это означает, что ваша область действия на уровне сеанса может работать в одном окне с сеансом в памяти, но если вы развернете в ферму сеанс SQL или службу сеанса, все рухнет, потому что сеанс не может сериализоваться ваш сохраненный объем. Если вы решите не сериализовать область действия, то у вас будет разная область действия для каждого пользователя на разных компьютерах, что также является потенциальной проблемой. - Сессия не всегда регидратирована. Если обработчик, к которому осуществляется доступ (например, веб-форма), не реализует IRequiresSessionState, сеанс не будет повторно сгенерирован (независимо от того, используется он в процессе или нет). Веб-формы и MvcHandler реализуют это по умолчанию, поэтому вы не увидите никаких проблем, но если у вас есть пользовательские обработчики, требующие внедрения, вы столкнетесь с некоторыми трудностями, поскольку для этих запросов "Session" не будет.
- Session_End не всегда срабатывает. Согласно документации по SessionStateModule.End, если вы используете состояние сеанса вне процесса, вы фактически не получите событие Session_End, поэтому вы не сможете очистить.
Учитывая ограничения, как правило, лучше стараться держаться подальше от областей, сохраняемых в сеансах. Однако... если это то, что вы собираетесь делать, то ILifetimeScopeProvider
это способ сделать это.