自定义成员资格提供程

时间:2011-06-29 10:01:37

标签: asp.net-mvc-3 dependency-injection unity-container membership

我有ASP.NET MVC3项目,我想使用自定义成员资格提供程序。另外,我想使用Unity来解析我的依赖注入。

这是来自Global.asax的代码:

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        var container = new UnityContainer();
        container.RegisterType<IAuthentification, Authentification>();
        container.RegisterType<IRepository, Repository>();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

    }

这是来自我的会员提供商的代码:

public class CustomMembershipProvider : MembershipProvider
{
   [Dependency]
   private IProveaRepository Repository { get; set; }

   public override bool ValidateUser(string username, string password)
    {
       .....
    }

问题是当我将断点放到ValidateUser方法时,我看到Repository属性没有初始化。但这种结构:

   [Dependency]
   private IProveaRepository Repository { get; set; }
例如,

在控制器中工作正常。

有人知道为什么会这样,该怎么办?

3 个答案:

答案 0 :(得分:17)

过去几天我遇到了同样的问题。我最终得到了以下解决方案(更改了类型和字段名称以匹配您的)。

public class CustomMembershipProvider : MembershipProvider       
{
    private IProveaRepository repository;

    public CustomMembershipProvider() 
        : this (DependencyResolver.Current.GetService<IProveaRepository>())
    { }

    public CustomMembershipProvider(IProveaRepository repository)
    {
        this.repository= repository;
    }

    public override bool ValidateUser(string username, string password)
    {
        ...
    }
}

因此,即使Unity无法控制CustomMembershipProvider的构建,无参数构造函数也会通​​过MVC3 DependencyResolver调用Unity来提供正确的存储库实例。

如果您正在对CustomMembershipProvider进行单元测试,那么您可以直接使用Unity构建一个实例,它将使用第二个构造函数并避免调用DependencyResolver

答案 1 :(得分:1)

Unity无法将IProveaRepository实例注入您的自定义成员资格提供程序,因为:

  • 您没有将其配置为执行此操作
  • CustomMembershipProvider不是由unity解决的,因此无法控制向其中注入依赖项

如果您在代码中使用了成员资格priovider类,则可以执行以下操作:

尝试将customMembershipProvider包装在抽象中,例如IMembershipProvider,它只对您使用的方法签名。结果是这样的:

public class CustomMembershipProvider : MembershipProvider, IMembershipProvider

然后你可以统一注册:

container.RegisterType<IMembershipProvider, CustomMembershipProvider>(new InjectionProperty(new ResolvedParameter<IProveaRepository>()));

然后约束是在控制器中传递依赖关系:

public class HomeController : Controller
{
 private IMembershipProvider _membershipprovider;
 public HomeController(IMembershipProvider membershipProvider)
 {
   _membershipProvider = membershipProvider
 }
 // some actions
}

但最好不要使用属性注入,而是构造函数注入:

public class CustomMembershipProvider : MembershipProvider
{
   private IProveaRepository Repository { get; set; }

   public CustomMembershipProvider(IProveaRepository proveaRepository)
   {
     Repository = proveaRepository
   }

   public override bool ValidateUser(string username, string password)
    {
       .....
    }

这是我理解它的方式并且会这样做。但也许有更好的方法,或者我忽略了一些有助于实现它的Unity API。

无论如何,我希望它有所帮助。

答案 2 :(得分:0)

虽然其他人说Unity不能在提供商中注入依赖关系,因为他们不知道 对于容器而言,即使可能是供应商的注册,您也没有通过容器构建供应商的“工厂点”,这是一个不违反良好设计原则的解决方案。 (这是因为,即使大多数人忽略了这一点,使用ServiceFactory也太靠近反模式......)

但是,一个好的解决方案可能是将[Dependency]属性与Unity BuildUp方法结合使用的关联。

所以以你的榜样为例,得到你想要做的事情,保留所有的东西,并在提供者构造函数中加入 BuildUp 调用

public class CustomMembershipProvider : MembershipProvider
{
   [Dependency]
   private IProveaRepository Repository { get; set; }

   public CustomMembershipProvider()
   {
     //contextual obtained container reference 
     unityContainer.BuildUp(this);
     .....
   }
   public override bool ValidateUser(string username, string password)
   {
       .....
   }

我希望它有所帮助。