Unity dependency injection in custom membership pr

2019-04-08 09:23发布

问题:

I have ASP.NET MVC3 project where I want to use custom membership provider. Also I want to use Unity for resolving my dependency injection.

this is code from 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));

    }

this is code from my membership provider:

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

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

Problem is when I put breakpoint to ValidateUser method I see that Repository property not initialized. But this construction:

   [Dependency]
   private IProveaRepository Repository { get; set; }

for example, works fine in controllers.

Does anybody know why it is so and what to do?

回答1:

I had the same problem over the last couple of days. I ended up with the following solution (type and field names changed to match yours).

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)
    {
        ...
    }
}

So even though Unity is not in control of the building of the CustomMembershipProvider, the parameterless constructor gets Unity involed (via the MVC3 DependencyResolver) to supply the correct repository instance.

If you're unit testing the CustomMembershipProvider then you can just build an instance with Unity directly, which will use the second constructor and avoid the call to DependencyResolver.



回答2:

Unity cannot inject IProveaRepository instance into you custom membership provider because :

  • You did not configured it to do so
  • CustomMembershipProvider is not resolved by unity so it has no control on injecting into it the dependencies

If you're using your membership priovider class in your code you could do the following :

Try to wrapp your customMembershipProvider in an abstraction for example IMembershipProvider that has only signature for methods that you use. The result is like that :

public class CustomMembershipProvider : MembershipProvider, IMembershipProvider

Then you could register it in unity :

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

Then the constraint is to pass the dependency in your controller like that :

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

But it would be event better to not user the property injection but the constructor injection like that :

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

   public CustomMembershipProvider(IProveaRepository proveaRepository)
   {
     Repository = proveaRepository
   }

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

It's the way I understand it and would do it. But maybe there is a better approach or I'm ignoring some of Unity API that would help to achieve it easier.

Anyway I hope it helps.



回答3:

While as others said Unity cannot inject dependencies in providers because they're not known to the container and, even if could be a registration of a provider, you haven't a "factory point" where building the provider through the container, there's a solution which doesn't violate good design principles. (This because, even if most people ignore this, using a ServiceFactory is too close to an antipattern...)

But, a good solution could be the association of using the [Dependency] attribute in conjunction with the Unity BuildUp method.

So taking your example, to get what you're trying to do, leave all the things as they are, and put in the provider constructor the BuildUp call

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)
   {
       .....
   }

I hope it helps.