asp.net-mvc - 每个 Web 请求的 EF DbContext + Custom RoleProvider = 每个 Web 请求或单例的 RoleProvider?

标签 asp.net-mvc dependency-injection singleton asp.net-roles simple-injector

使用 EF DbContext包装在接口(interface)中,根据 Web 请求注入(inject)依赖项,以确保整个请求处理相同的上下文。还有一个自定义RoleProvider消耗了 DbContext通过接口(interface)自定义授权服务。

到目前为止,我一直在使用服务定位器模式来解决 DbContext自定义中的实例 RoleProvider的无参数构造函数。这导致了一些小问题,因为 RoleProvider是单例的,所以它可能持有 DbContext无限期地,而其他请求可能希望在 Application_EndRequest 期间处理它.

我现在有一个解决方案based on this ,尽管使用与温莎不同的 ioc 容器。我可以使用 DI 新建自定义 RoleProvider每个 http 请求的实例。

我的问题是,我应该吗?

有一个开放的DbContext挂掉 RoleProvider似乎很浪费。另一方面,我知道每个 MVC AuthorizeAttribute点击 RoleProvider (如果它有一个非空的 Roles 属性,我们大多数人都有)所以我想它可能是有用的已经有一个 DbContext在等待中。

另一种方法是注入(inject)一个不同的 DbContext对于 RoleProvider那不是每个网络请求。这样DbContext只为 web 请求而活的 s 可以在最后处理,而不影响单例 RoleProvider .

哪种方法更好,为什么?

评论后更新

Steven,这基本上就是我所做的。唯一的区别是我不依赖 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)
}

网络配置:

<roleManager enabled="true" defaultProvider="InjectedRoleProvider">
    <providers>
        <clear />
        <add name="InjectedRoleProvider" type="MyApp.InjectedRoleProvider" />
    </providers>
</roleManager>

IoC 容器:

Container.RegisterPerWebRequest<RoleProvider, CustomRoleProvider>();

至于 CUD,在我的 CustomRoleProvider 中只实现了 1 个方法:

public override string[] GetRolesForUser(string userName)

这是 MVC 的 AuthorizeAttribute 使用的唯一方法(和 IPrincipal.IsInRole ),以及所有其他方法,我只是

throw new NotSupportedException("Only GetRolesForUser is implemented.");

由于供应商没有角色 CUD 操作,我不担心交易。

最佳答案

看看 Griffin.MvcContrib项目。它包含使用 MVC DependencyResolverMembershipProviderRoleProvider 实现。

您可以像这样配置 RoleProvider:

<roleManager enabled="true" defaultProvider="MvcRoleManager">
  <providers>
    <clear />
    <add name="MvcRoleManager" 
      type="Griffin.MvcContrib.Providers.Roles.RoleProvider, Griffin.MvcContrib"
    />
  </providers>
</roleManager>

它使用 System.Web.MVC DependencyResolver 类,因此您需要为您正在使用的 DI 容器配置一个 IDependencyResolver 实现。使用 Simple Injector(和 SimpleInjector.MVC3 integration NuGet package),您需要在 Application_Start 事件中进行以下配置:

container.RegisterAsMvcDependencyResolver();

Griffin.MvcContrib.Providers.Roles.RoleProvider 依赖于同一程序集中定义的 IRoleRepository。您现在不必实现完整的角色提供程序,只需实现 IRoleRepository 并将其注册到您的容器中即可:

container.Register<IRoleRepository, MyOwnRoleRepository>();

你可以找到这个项目here在 NuGet 上。

更新

现在让我们回答这个问题:

Griffin.MvcContrib RoleProvider 将是单例的,现在问题转移到 IRoleRepository 及其依赖项,但问题确实仍然存在。

如果你所做的只是从角色提供者读取(从不更新数据库);在这种情况下,您选择哪个生命周期并不重要,只要您不在线程上重用相同的 DbContext

但是,当您确实使用角色提供程序来更新数据库时,情况就不同了。在那种情况下,我会给它自己的上下文,并让它在每次操作后显式提交。因为如果您不这样做,谁来进行这些更改?当在命令处理程序(尤其是 TransactionCommandHandlerDecorator)的上下文中运行时,操作将在命令成功后提交,并在命令失败时回滚。当命令失败时回滚该更改也许很好。但是当角色提供者在命令处理程序的上下文之外运行时,谁来提交它呢?我相信您将能够解决这个问题,但我相信您最终会得到一个难以掌握的系统,它会让试图找出这些更改未提交的原因的其他开发人员眼花缭乱。

关于asp.net-mvc - 每个 Web 请求的 EF DbContext + Custom RoleProvider = 每个 Web 请求或单例的 RoleProvider?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9828448/

相关文章:

java - 无法 Autowiring 方法

c# - 通过 SimpleInjector 注册单例并返回相同的实例,对于它实现的不同接口(interface)

java - android:应用程序关闭后,单例实例不会被垃圾回收

singleton - Pthread Thread-Local-Singleton,何时释放 TLS Key?

c# - .NET中双重检查锁定中对volatile修饰符的需求

c# - Entity Framework : Check all relationships of an entity for foreign key use

asp.net-mvc - Windows 中的 ASP.NET MVC 路由与保留文件名

android - 是否有关于 Dagger 在注入(inject)依赖项时何时回退到反射的文档?

asp.net-mvc - OutputCache Controller 属性因用户角色而异吗? .net MVC中可能吗?

c# - SubSonic 3.0 简单存储库向对象添加 DateTime 属性