Question

I have a custom MembershipProvider class that inherits from MembershipProvider that takes two parameters:

public class CustomMembershipProvider : MembershipProvider
{
    private readonly ISecurityRepository _securityRepository;
    private readonly IUserRepository _userRepository;

    public CustomMembershipProvider(ISecurityRepository securityRepository, IUserRepository userRepository)
    {
        ...
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        ...
    }

    ... etc
}

The config file for this looks similar to this:

<membership defaultProvider="CustomMembershipProvider">
  <providers>
    <clear />
    <add name="CustomMembershipProvider" type="Library.Membership.CustomMembershipProvider" />
  </providers>
</membership>

This works fine mostly throughout my web application for logging in and logging out. I am using Unity for DI and have the necessary classes setup in my Boostrapper.cs class.

However I recently ran into an issue when I wanted to create a custom User class and called the Membership.GetUser method. I get the following exception when I do:

{"No parameterless constructor defined for this object. (C:\\*app path*\\web.config line 43)"}

Line 43 in my config file points to the custom membership provider that I posted above. I think that elsewhere the app is using Unity to resolve those parameters but when using the Membership class it doesn't.

Is there any way I can tell the application how to resolve those dependencies or if not is there a way of adding those dependencies to my membership provider without using the concrete implementation?

EDIT 1:

Here is the custom User class:

public class User : MembershipUser
{
    public int UserId { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
    public DateTime LastLoggedOnDate { get; set; }
    ...         
}

EDIT 2:

In my custom membership provider class this is what the GetUser method looks like:

public override MembershipUser GetUser(string username, bool userIsOnline)
{
    return _userRepository.GetUser(username);
}
Was it helpful?

Solution

The problem is that you can't inject into the Membership provider via constructor. Refer to this question

I implemented a Custom Membership Provider using Ninject and I used the ServiceLocator to get the instance of the service.

public class AccountMembershipProvider : MembershipProvider
{
    private readonly IUsers _users;

    public AccountMembershipProvider()
    {
        _users = ServiceLocator.Current.GetInstance<IUsers>();
    }

    public override bool ValidateUser(string username, string password)
    {
        return _users.IsValidLogin(username, password);
    }
...
}

In your case, you need to get the IUserRepository and ISecurityRepository.

When you wire your Interfaces/services

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IUsers>().To<UsersService>();
        kernel.Bind<IRoles>().To<RolesService>();

        kernel.Bind<MembershipProvider>().To<AccountMembershipProvider>().InRequestScope();
        kernel.Bind<RoleProvider>().To<AccountRoleProvider>().InRequestScope();

    }

You can check a complete example of it working (using Ninject but you can adapt it to Unity) here: https://github.com/lopezbertoni/SampleApp

Hope this helps,

OTHER TIPS

I also use Unity and implemented a custom membership provider, but used a slightly different approach. Check the code sample:

/// <summary>
/// Defines the custom membership provider class.
/// </summary>
public class SsoMembershipProvider : MembershipProvider
{


    private IApplicationsRepository _appsRepo;
    private IUsersRepository _usersRepo;
    private IMembershipsRepository _membershipsRepo;



    /// <summary>
    /// Initializes a new instance of the <see cref="SsoMembershipProvider"/> class
    /// using injectionConstructor attribute in order to get the repositories needed.
    /// </summary>
    /// <param name="appsRepo">The apps repo.</param>
    /// <param name="usersRepo">The users repo.</param>
    /// <param name="membershipsRepo">The memberships repo.</param>
    [InjectionConstructor]
    public SsoMembershipProvider(IApplicationsRepository appsRepo, IUsersRepository usersRepo, IMembershipsRepository membershipsRepo)
    {
        _appsRepo = appsRepo;
        _usersRepo = usersRepo;
        _membershipsRepo = membershipsRepo;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SsoMembershipProvider"/> class.
    /// which calls the internal contructor.
    /// </summary>
    /// <remarks>This is happening due to the fact that membership provider needs a
    /// parametless constructor to be initialized</remarks>
    public SsoMembershipProvider()
        : this(DependencyResolver.Current.GetService<IApplicationsRepository>(),
        DependencyResolver.Current.GetService<IUsersRepository>(),
        DependencyResolver.Current.GetService<IMembershipsRepository>())
    { }


}

This worked for me

public ICustomerRepository CustomerRepository { 
 get { return DependencyResolver.Current.GetService<ICustomerRepository>(); } 
}

and then use

public override bool ValidateUser(string username, string password)
{
    var abc = CustomerRepository.ValidateCustomer(username, password);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top