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);
}
}
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.