Используя EF DbContext
, завернутый в интерфейс (ы), зависимость вводится для каждого веб-запроса, чтобы убедиться, что весь запрос работает с одним и тем же контекстом.Также есть пользовательский RoleProvider
, который использует интерфейс DbContext
для настройки служб авторизации.
До сих пор я использовал шаблон локатора служб для разрешения экземпляра DbContext
в пользовательских RoleProvider
.безошибочный конструктор.Это вызвало некоторые незначительные проблемы, потому что RoleProvider
является однотонным, поэтому он может удерживать DbContext
бесконечно, тогда как другие запросы могут захотеть утилизировать его во время Application_EndRequest
.
Теперь у меня есть решение , основанное на этом , хотя с использованием контейнера ioc, отличного от windsor.Я могу использовать DI для создания нового экземпляра RoleProvider
для каждого http-запроса.
У меня такой вопрос, должен ли я?
Наличие открытого DbContext
зависанияот RoleProvider
кажется расточительным.С другой стороны, я знаю, что каждый MVC AuthorizeAttribute
достигает RoleProvider
(если у него есть ненулевое свойство Roles
, что есть у большинства из нас), поэтому я полагаю, что было бы полезно иметь уже DbContext
в ожидании.
В качестве альтернативы можно ввести другое DbContext
для RoleProvider
, которое отсутствует для веб-запроса.Таким образом, DbContext
, которые существуют только для веб-запроса, могут быть расположены в конце, не влияя на одиночный RoleProvider
.
Является ли какой-либо подход лучше и почему?
Обновление после комментариев
Стивен, это по сути то, что я и сделал.Разница лишь в том, что я не беру зависимость от System.Web.Mvc.DependencyResolver
.Вместо этого у меня в основном есть та же самая вещь в моем собственном проекте, только названная по-другому:
public interface IInjectDependencies
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
public class DependencyInjector
{
public static void SetInjector(IInjectDependencies injector)
{
// ...
}
public static IInjectDependencies Current
{
get
{
// ...
}
}
}
Эти классы являются частью основного API проекта и находятся в другом проекте, чем MVC.Таким образом, этот другой проект (наряду с доменным проектом) не должен принимать зависимость от System.Web.Mvc
, чтобы компилировать его DependencyResolver
.
Учитывая эту структуру, заменяя Unity с SimpleInjectorдо сих пор безболезненноВот как выглядит многоцелевая одиночная установка RoleProvider:
public class InjectedRoleProvider : RoleProvider
{
private static IInjectDependencies Injector
{ get { return DependencyInjector.Current; } }
private static RoleProvider Provider
{ get { return Injector.GetService<RoleProvider>(); } }
private static T WithProvider<T>(Func<RoleProvider, T> f)
{
return f(Provider);
}
private static void WithProvider(Action<RoleProvider> f)
{
f(Provider);
}
public override string[] GetRolesForUser(string username)
{
return WithProvider(p => p.GetRolesForUser(username));
}
// rest of RoleProvider overrides invoke WithProvider(lambda)
}
Web.config:
<roleManager enabled="true" defaultProvider="InjectedRoleProvider">
<providers>
<clear />
<add name="InjectedRoleProvider" type="MyApp.InjectedRoleProvider" />
</providers>
</roleManager>
Контейнер IoC:
Container.RegisterPerWebRequest<RoleProvider, CustomRoleProvider>();
Что касается CUD, то здесьЭто только 1 метод, реализованный в моем CustomRoleProvider
:
public override string[] GetRolesForUser(string userName)
Это единственный метод, используемый MVC AuthorizeAttribute
(и IPrincipal.IsInRole
), и из всех других методов я просто
throw new NotSupportedException("Only GetRolesForUser is implemented.");
Поскольку у провайдера нет роли CUD, я не беспокоюсь о транзакциях.