使用包含在接口中的EF DbContext
,为每个Web请求注入依赖项,以确保整个请求处理相同的上下文。还有一个自定义RoleProvider
,它使用DbContext
接口来自定义授权服务。
到目前为止,我一直在使用服务定位器模式来解析自定义DbContext
的无参数构造函数中的RoleProvider
实例。这导致了一些小问题,因为RoleProvider
是单一的,因此它可能会无限期地保留DbContext
,而其他请求可能希望在Application_EndRequest
期间处理它。
我现在有一个解决方案based on this,但使用的是与windsor不同的ioc容器。我可以使用DI为每个http请求新建一个自定义RoleProvider
实例。
我的问题是,我应该吗?
DbContext
悬空RoleProvider
似乎很浪费。另一方面,我知道每个MVC AuthorizeAttribute
都会点击RoleProvider
(如果它有一个非null Roles
属性,我们大多数都属于这个属性)所以我想它可能对已经等待了DbContext
。
另一种方法是为不是每个网络请求的DbContext
注入不同的RoleProvider
。这样,只能为Web请求生效的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
。
鉴于该框架,使用SimpleInjector交换Unity到目前为止一直很轻松。以下是多用途单例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,我的CustomRoleProvider
中只实现了一种方法:
public override string[] GetRolesForUser(string userName)
这是MVC的AuthorizeAttribute
(和IPrincipal.IsInRole
)使用的唯一方法,而且从其他所有方法来看,我只是
throw new NotSupportedException("Only GetRolesForUser is implemented.");
由于CUD操作系统上没有角色,我不担心交易。
答案 0 :(得分:3)
看看Griffin.MvcContrib项目。它包含使用MVC MembershipProvider
的{{1}}和RoleProvider
实现。
您可以像这样配置DependencyResolver
:
RoleProvider
它使用System.Web.MVC <roleManager enabled="true" defaultProvider="MvcRoleManager">
<providers>
<clear />
<add name="MvcRoleManager"
type="Griffin.MvcContrib.Providers.Roles.RoleProvider, Griffin.MvcContrib"
/>
</providers>
</roleManager>
类,因此您需要为正在使用的DI容器配置DependencyResolver
实现。使用Simple Injector(和SimpleInjector.MVC3 integration NuGet package),您需要在IDependencyResolver
事件中进行以下配置:
Application_Start
container.RegisterAsMvcDependencyResolver();
依赖于在同一程序集中定义的Griffin.MvcContrib.Providers.Roles.RoleProvider
。您现在可以只实现IRoleRepository
并将其注册到容器中,而不必实现完整的角色提供程序:
IRoleRepository
您可以在NuGet上找到此项目here。
<强>更新强>
现在让我们回答这个问题:
Griffin.MvcContrib RoleProvider将是单例,现在问题转移到container.Register<IRoleRepository, MyOwnRoleRepository>();
及其依赖关系,但问题确实仍然存在。
如果您从角色提供程序中读取所有内容(从不更新数据库);在这种情况下,只要您不在线程上重复使用相同的IRoleRepository
,您选择的生命周期并不重要。
但是,当您使用角色提供程序更新数据库时,情况会有所不同。在这种情况下,我会给它自己的上下文,让它在每次操作后显式提交。因为如果你不这样做,谁将承诺进行这些改变?在命令处理程序(尤其是TransactionCommandHandlerDecorator)的上下文中运行时,操作将在命令成功后提交,并在命令失败时回滚。也许在命令失败时将该更改回滚可以。但是当角色提供程序在命令处理程序的上下文之外运行时,谁将提交它?我相信你能够解决这个问题,但我相信你最终会得到一个难以掌握的系统,它会让那些试图找出这些改变没有提交的开发人员感到眩目。