Inject repository to custom membership provider with Ninject

I'm trying to inject a repository to a custom membership provider with ninject in MVC 3.

In MembershipProvider I have tried the following:

[Inject]
public ICustomerRepository _customerRepository{ get; set; }

And

[Inject]
public TUMembershipProvider(ICustomerRepository customerRepository)
{
    _customerRepository = customerRepository;
}

In my ninject module i tried the following:

Bind<MembershipProvider>().ToConstant(Membership.Provider);

None of the above works.

When i use(in global.asa)

kernel.Inject(Membership.Provider);

together with

[Inject]
public ICustomerRepository _customerRepository{ get; set; }

it works, but i have no life cycle management and this will cause a "ISession is open" error from NHibernate, because the ISession is InRequestScope and the repository is not.


Solution 1:

You could use the approach @Remo Gloor outlines in his blog post on provider injection. It involves 3 steps:

  1. Add [Inject]s to any properties on your provider you need injected (although the pattern he shows -- creating a very simple class whose only function is to be a receptable for property injection and forwards any requests to a real class implemented using constructor injection -- is well worth following)

    public class MyMembershipProvider : SqlMembershipProvider
    {
        [Inject]
        public SpecialUserProvider SpecialUserProvider { get;set;}
        ...
    
  2. Create an initializer wrapper that implements IHttpModule which pulls the provider in, triggering its creation:-

    public class ProviderInitializationHttpModule : IHttpModule
    {
        public ProviderInitializationHttpModule(MembershipProvider membershipProvider)
        {
        }
    ...
    
  3. Register the IHttpModule in your RegisterServices :-

    kernel.Bind<IHttpModule>().To<ProviderInitializationHttpModule>();
    
  4. there is no 4; Ninject does the rest - bootstrapping all registered IHttpModules including the one you added) during the startup sequence.

(Don't forget to read the comments on the blog post re lifetimes etc.)


Finally, if you're looking for something completely braindead direct that solves it neatly, try this @Remo Gloor answer instead


PS a great writeup on the whole mess is Provider is not a Pattern by @Mark Seemann. (and the oboligatory plug for his excellent book:- Dependency injection in .NET which will have you figuring this stuff out comfortably from first principles)

Solution 2:

i had this problem

a custom membership, role and profile provider in another project from MVC using repository, when ever i call the provider the injected repository was null.

tried to call kernel.Inject(Membership.Provider); in the NinjectWebCommon method registerServices(IKernel kernel) but got the exception

The result is always null, because asp.net has it's own static property for membership.which is membership.provider. and this instance is not part of instance ninject management.

so use on PostApplicationStartMethod

here is the soloution by cipto add to NinjectWebCommon the attrbute and method :

    [assembly: WebActivator.PreApplicationStartMethod(typeof(WebApp.App_Start.NinjectWebCommon), "Start")]
    [assembly: WebActivator.PostApplicationStartMethod(typeof(WebApp.App_Start.NinjectWebCommon), "RegisterMembership")]
    [assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(WebApp.App_Start.NinjectWebCommon), "Stop")]

    public static void RegisterMembership()
    {
        bootstrapper.Kernel.Inject(Membership.Provider);
    } 

Solution 3:

The problem is that the whole Membership infrastructure is a "native" .NET code (System.Web.Security) that does not know about MVC and about the DI container used by MVC. The static call to Membership.Provider returns the membership provider based on the configuration, however, the specified provider type is instantiated with a simple Activator.CreateInstance call. Hence, the dependency injection has no chance to kick in and set your repository dependency on the result. If you explicitly setup the returned instance with Ninject it can work, because you explicitly gave Ninject the object to set the dependencies. Even in this case it can only work with property injection and not with constructor injection, because the instance is created by the membership configuration previously.

To summarize: you cannot easily inject dependencies into the membership provider because it is not resolved from a dependency injection container. I think you have 2 possibilities:

  1. You create a repository in the custom membership provider directly or you access it by some other means on demand (where the web context is already present).
  2. You go one level higher and check the components that would use your membership provider and you try change there (to use a membership provider resolved from your DI container instead of the uninitialized Memership.Provider). If this "higher component" is the forms authentication, then this article might be of help (using dependency injection with IFormsAuthentication and IMembershipService): http://weblogs.asp.net/shijuvarghese/archive/2009/03/12/applying-dependency-injection-in-asp-net-mvc-nerddinner-com-application.aspx