Search code examples
c#asp.net-mvcdbcontextsqlconnectionuser-roles

Custom Role Provider - {"The connection was not closed. The connection's current state is connecting."}


I've implemented a Custom Role Provider in my MVC application but when multiple simultaneous Authorize requests are made I get the following error {"The connection was not closed. The connection's current state is connecting."}

this happens on the line within my UserRepository file.

var user = _db.Users.SingleOrDefault(u => u.userName == username);

Suggestions from other threads on here are that I should instantiate the _db Context separately within each method of my UserRepository file. This does indeed resolve the problem, however I have read elsewhere that I should be using ISession for shared DataContexts.. The application will only have one DataContext but multiple repositories that use this. So I would be really greatful if someone could just confirm that by moving the _db Context to the start of each method i'm doing the right thing before I get head long in to this project.

Thanks in advance

I've attached the relevant files below in the order they execute.

File: Global.asax.cs

void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie != null)
        {
            string encTicket = authCookie.Value;
            if (!String.IsNullOrEmpty(encTicket))
            {
                var ticket = FormsAuthentication.Decrypt(encTicket);
                var id = new UserIdentity(ticket);
                var userRoles = Roles.GetRolesForUser(id.Name); //Method in Question
                var prin = new MyPrincipal(id, userRoles);
                string userData = ((FormsIdentity)(Context.User.Identity)).Ticket.UserData;
                var serializer = new JavaScriptSerializer();
                prin.User = (User)serializer.Deserialize(userData, typeof(User));
                HttpContext.Current.User = prin;
            }
        }
    }

File: CustomRoleProvider.cs

namespace CMS3.Infrastructure
{
public class CustomRoleProvider : RoleProvider
{
    private ILoginRepository _rep;

    public CustomRoleProvider(ILoginRepository rep)
    {
        _rep = rep;
    }

    public CustomRoleProvider()
        : this(new UserRepository())
    { }


    public override string[] GetRolesForUser(string username)
    {
        var roles = _rep.GetRolesForUser(username);
        return roles;
    }
}
}

File: userRepository.cs

namespace CMS3.Ef.Repositories
{
public class UserRepository : ILoginRepository
{
    CMS3Context _db = new CMS3Context();
    static PasswordManager pwdManager = new PasswordManager();
 string[] ILoginRepository.GetRolesForUser(string username)
    {
            var user = _db.Users.SingleOrDefault(u => u.userName == username);
            if (user == null)
                return new string[] { };
            return user.UserRoles == null ? new string[] { } : user.UserRoles.Select(u =>u.Role).Select(u => u.roleName).ToArray();

    }
}

File: ILoginRepository.cs

namespace CMS3.Model.InterfaceRepositories
{
public interface ILoginRepository : IDisposable
{
    tblLogin UserByID(int id);
    LoginDetails UserByNamePassword(string userName, string password);
    LoginDetails UserByName(string userName);
    bool IsUserInRole(string username, string roleName);
    string[] GetRolesForUser(string username);
    string[] GetAllRoles();
    List<UsersSearchDetails> GetUsers(int count = 0);
    List<UsersSearchDetails> GetUsers(string searchUser);
    UsersSearchDetails GetUser(int id);
    bool AdminChangePassword(int id, string newPassword);
    bool deActivateUser(int id);
    List<RoleDetails> getUserRoles(int id);
    List<RoleDetails> getAvaiableRoles(int id);
    bool AddRoleToUser(int id, int role);
    bool RemoveRoleFromUser(int id, int role);
    bool UpdateLoginStatus(string userName, bool loginFail);
    string[] SearchUsers(string term);
}

}


Solution

  • Suggestions from other threads on here are that I should instantiate the _db Context separately within each method of my UserRepository file. [...] So I would be really greatful if someone could just confirm that by moving the _db Context to the start of each method i'm doing the right thing before I get head long in to this project.

    That is completely opposite of what you should do. Having an extra dbcontext per repository means that the benefit of the first-level cache (the identity map) is lost, each repository caches data on its own.

    Instead, you should make the repository implementation depend on the external way of dbcontext's lifetime management:

    public class UserRepository : ILoginRepository
    {
        CMS3Context _db;
    
        public UserRepository( CMS3Context db )
        {
            this._db = db;
        }
    
        ...
    }
    

    This way, you inject the context, shared or not, for example, in your MVC application you would usually have a single context per http request.