Использование EF DbContext
, завернутый в интерфейсы (интерфейсы), вложенные в запрос для каждого запроса, чтобы убедиться, что весь запрос имеет дело с одним и тем же контекстом. Также у вас есть пользовательский RoleProvider
, который использует интерфейс DbContext
для настройки служб авторизации.EF DbContext для веб-запроса + Пользовательский RoleProvider = RoleProvider для веб-запроса или singleton?
До сих пор я использовал шаблон локатора службы для разрешения экземпляра DbContext
в пользовательском конструкторе no-arg RoleProvider
. Это вызвало некоторые незначительные проблемы, поскольку RoleProvider
является однотонным, поэтому он может удерживаться на DbContext
бесконечно, тогда как другие запросы могут захотеть избавиться от него во время Application_EndRequest
.
У меня теперь есть решение based on this, хотя я использую другой контейнер ioc, чем виндзор. Я могу использовать DI для создания настраиваемого экземпляра RoleProvider
для каждого HTTP-запроса.
Вопрос в том, должен ли я?
Имея открытый DbContext
, висит от RoleProvider
кажется расточительным. С другой стороны, я знаю, что каждый MVC AuthorizeAttribute
попадает в RoleProvider
(если у него есть нулевое свойство Roles
, что у большинства наших), я полагаю, что может быть полезно уже иметь DbContext
в ожидании.
Альтернативой было бы ввести другой DbContext
для RoleProvider
, который не является веб-запросом. Таким образом, DbContext
s, которые живут только для веб-запроса, могут быть расположены в конце, не затрагивая однотонный RoleProvider
.
Является ли подход лучше, и почему?
Update после комментариев
Стивен, это по существу то, что я сделал. Единственное различие заключается в том, что я не беру зависимость от 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 до сих пор была безболезненной. Вот что представляет собой многоцелевая установка SinglePort 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)
}
Веб.конфигурации:
<roleManager enabled="true" defaultProvider="InjectedRoleProvider">
<providers>
<clear />
<add name="InjectedRoleProvider" type="MyApp.InjectedRoleProvider" />
</providers>
</roleManager>
IoC контейнер:
Container.RegisterPerWebRequest<RoleProvider, CustomRoleProvider>();
Что касается жвачку, есть только один метод, реализованный в моем CustomRoleProvider
:
public override string[] GetRolesForUser(string userName)
Это единственный метод, используемый MVC-х AuthorizeAttribute
(и IPrincipal.IsInRole
), и из всех других методов я просто
throw new NotSupportedException("Only GetRolesForUser is implemented.");
Поскольку на провайдере нет роли CUD ops, я не беспокоюсь о транзакциях.
Можете ли вы реализовать свой собственный «RoleService», а не использовать «RoleProvider»? «RoleProvider» не очень дружелюбен к МОК. – Dismissile
@ Disismile Я стараюсь держать все как можно проще. Я не знаю, с чего начать, если подключить RoleService к 'IPrincipal.IsInRole (string)'. Это не сложно было обернуть и контролировать свою жизнь, используя ссылку в моем вопросе. Теперь я хочу знать, какой срок жизни я должен использовать. – danludwig
Выполняете ли вы проверку подлинности Windows или проверку подлинности с помощью форм? Вы используете встроенную базу данных членства ASP.net? Если вы используете либо Windows, либо стандартную базу данных членства, это, вероятно, не так просто. Если вы храните пользователей/роли в своей собственной схеме базы данных, то, вероятно, это не намного сложнее, чем запрашивать эту таблицу для конкретного пользователя, чтобы увидеть, в каких ролях они находятся. – Dismissile