7

How do I communicate with the UserService through an overidden MembershipProvider class? I have no idea how to pass the connection string to the user repository inside the service.

This is how my app is structured:

Repository (constructor in the implementation takes a connection string)

public interface IUserRepository
{
    IQueryable<User> GetUsers();
    IQueryable<UserRole> GetUserRoles();
    void InsertUser(User user);
}

Service (Constructor takes a user repository)

public interface IUserService
{
    User GetUser(int userId);
    User GetUser(string email);
}

UserController (An example of my controller)

public class UsersController : Controller
{
    private IUserService userService;
    public UsersController(IUserService userServ)
    {
        userService = userServ;
    }
}

NinjectConfigurationModule

public class NinjectConfigurationModule : NinjectModule
{

    public override void Load()
    {
        Bind<IUserService>().To<UserService>();
        Bind<IUserRepository>().To<UserRepository>()
            .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString
            );
    }
}

NinjectControllerFactory

public class NinjectControllerFactory : DefaultControllerFactory
{
    private IKernel kernel = new StandardKernel(new NinjectConfigurationModule());

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        // We don't want to pass null to ninject as we'll get a strange error.
        return controllerType == null ? null
                                      : (IController)kernel.Get(controllerType);
    }
}

MembershipProvider (This is where my problem is)

public class SimpleMembershipProvider : MembershipProvider
{
     //How do I set up User Service here so that ninject can put my connection string here.
     public override bool ValidateUser(string username, string password)
     {
           //Code to use user service.
     }
}
Shawn Mclean
  • 56,733
  • 95
  • 279
  • 406
  • possible duplicate of [Inject repository to custom membership provider with Ninject](http://stackoverflow.com/questions/5596441/inject-repository-to-custom-membership-provider-with-ninject) – Ruben Bartelink Aug 22 '12 at 21:06
  • See http://stackoverflow.com/a/10394860/11635 - I think Remo's solution doesnt get enough press and am very unimpressed with the answers to this question, which is the top google ranked answer for some reason. Realize no this one is much newer which makes me less confident in wanting this to be dup. They are both bad I reckon! – Ruben Bartelink Aug 22 '12 at 21:14

2 Answers2

19

Already answered question, but I think the better answer is to make the repository a property on your MembershipProvider and inject into it at Application_Start. e.g.

public class AccountMembershipProvider : MembershipProvider
{
    [Inject]
    public IAccountRepository AccountRepository { get; set; }
    ...
}

and the injection:

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

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

        // Inject account repository into our custom membership & role providers.
        _kernel.Inject(Membership.Provider);

        // Register the Object Id binder.
        ModelBinders.Binders.Add(typeof(ObjectId), new ObjectIdModelBinder()); 
    }

I've written up a more in depth explanation here:

http://www.danharman.net/2011/06/23/asp-net-mvc-3-custom-membership-provider-with-repository-injection/

DanH
  • 3,772
  • 2
  • 27
  • 31
  • A pleasure. I had some trouble working out how to do this myself, as there are a few questions on it here on SO, but the answers aren't that explicit, or even good. I've actually just redone the article an hour ago to be clearer. – DanH Jun 25 '11 at 01:08
  • That's a great way of getting around the annoying dependencies in a custom membership provider - this should be the answer – Dan Aug 19 '11 at 15:21
  • The problem here is that your MembershipProvider is no dependent on Ninject library. If you planned to put your MembershipProvider in a common library that doesn't carry around external dependencies, then you are out of luck. – crush Nov 20 '14 at 21:49
3

You can override the MembershipProvider.Initialize function and also need some settings in web.config

public override void Initialize(string name, NameValueCollection config) {
    // Validate arguments
    if (config == null) throw new ArgumentNullException("config");

    // Initialize base class
    base.Initialize(name, config);

    // Initialize current class
    this.configuration = config;
    System.Configuration.ConnectionStringSettings ConnectionStringSettings = System.Configuration.ConfigurationManager.ConnectionStrings[config["connectionStringName"]];
    if (ConnectionStringSettings == null || ConnectionStringSettings.ConnectionString.Trim() == "") throw new ProviderException("Connection string cannot be blank.");
    // then you can create a new user service using the connection string: SimpleAuthDb
}

web.config

<membership defaultProvider="MyMembershipProvider">
    <providers>
        <clear/>
        <add name="MyMembershipProvider"
             type="Web.SimpleSqlMembershipProvider"
             connectionStringName="SimpleAuthDb" />
    </providers>
</membership>

I also created a custom membership provider like you. in user controller's login action will call the validateuser function like this:

Membership.ValidateUser(userName, password);

but ultimately I give up the membership provider and add a new function ValidateUser in IUserService, and then the code like this:

userService.ValidateUser(userName, password);

I think this is more simple.

Liu Peng
  • 1,226
  • 2
  • 11
  • 13