Question

I'm having problems with custom membership within MVC 4 I keep getting a context lifetime related error when I do a ajax call to get a partial result from the server(controller), the error is always {"The provider has been closed"} or {"There is already an open DataReader associated with this Command which must be closed first."} the error always lands within the custom RoleProvider. I will try to explain the current setup im using.

I have inherited from the Membership and RoleProvier and overridden all the methods like so

public class CustomRoleProvider : RoleProvider
{
        private IAccountService _accountService;

        public CustomRoleProvider()
        {
            _accountService = new AccountService();
        }
        public override string[] GetRolesForUser(string username)
        {
             return _accountService.GetRolesForUser(username);
        }
}

The Membership provider is implemented in the same way the IAccountService above is the service layer that deals with all user accounts & roles all the service layer classes implement a base service class called ServiceBase that creates the DB context

public class ServiceBase
{
    protected Context Context;

    protected ServiceBase() : this("Context") {}

    protected ServiceBase(string dbName)
    {
        IDatabaseInitializer<Context> initializer = new DbInitialiser();
        Database.SetInitializer(initializer);
        Context = new Context(dbName);
    }
}

The Controller that has the ajax to made to it

[Authorize(Roles = "Administrator,Supplier")]
public class AuctionController : Controller
{
    private IAuctionService _service;

    public AuctionController()
    {
        _service = new AuctionService();
    }
    public AuctionController(IAuctionService service)
    {
        _service = service;
    }
    [CacheControl(HttpCacheability.NoCache), HttpGet]
    public ActionResult RefreshAuctionTimes(int auctionId)
    {
        return PartialView("_AuctionTimer", BusinessLogic.Map.ConvertAuction(_service.GetAuction  (auctionId)));
     }

}

The problem only started when I added the [Authorize(Roles = "Administrator,Supplier")] attribute to the controller that handled the ajax call, I know this is the lifetime of the DbContext being for the life of the app and the controllers service layer being destroyed and recreated on every post but I'm not sure of the best way to handle this, I have used this setup before but with DI and Windsor and never had this problem as the IOC was controlling the context.

Would it be best to create the providers its own DB context or is the conflict between the 2 providers and really they need to share the same db context?

Any help would be great thanks

Was it helpful?

Solution

The problem is exactly what you're suspecting. Is due to the fact that you're creating a single instance of the DbContext and therefore you're having connection issues. If you use it with an IOC/DI schema, you're going to fix it. The other option is to manually handle the connections.

An example of how to do this using Ninject as IOC container is here They need to share the same context in order for the problem to stop.

OTHER TIPS

I would suggest you create your service layer class on each call to GetRolesForUser:

public override string[] GetRolesForUser(string username)
{
     return new AccountService().GetRolesForUser(username);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top