3

I've implemented a custom RoleProvider for a project. The RoleProvider works, but the repository I use to fetch the user roles is only populated after build. When I logOff, change the role of the user, logOn again, the user still holds the old roles.

public class CmsRoleProvider : RoleProvider
{
    private EntityDB _db { get; set; }

    public CmsRoleProvider()
    {
        _db = new EntityDB();
    }

    public override string[] GetRolesForUser(string username)
    {
        var user = _db.Users.Where(u => u.EmailAddress == username).SingleOrDefault();
        var roles = user.UserRoles.Select(u => u.Role.Name).ToList<string>();

        return roles.ToArray();
    }
}

In the sample above, the user only get the correct roles after building the project. When I create the repository inside the GetRolesForUser function, it works fine.

Is there a caching problem going on? Who can help me with this.

Bassam Mehanni
  • 14,796
  • 2
  • 33
  • 41
jpderooy
  • 73
  • 1
  • 5

2 Answers2

7

ASP.NET creates only single instance of the RoleProvider. Because of that your context is also long lived. Better to have short lived contexts.

public class CmsRoleProvider : RoleProvider
{        
    private EntityDB GetContext()
    {
       return new EntityDB();
    }

    public override string[] GetRolesForUser(string username)
    {
        using(var db = GetContext())
        {
            var user = db.Users.Where(u => u.EmailAddress == username)
                          .SingleOrDefault();
            var roles = user.UserRoles.Select(u => u.Role.Name).ToList<string>();

            return roles.ToArray();
        }
    }
}

Problem with your approach is that context keeps track of the loaded users. When you ask for a user that is already tracked by the context the existing instance is returned. Hence the UserRoles associated with that is returned.

Eranga
  • 32,181
  • 5
  • 97
  • 96
  • Thanks! I fixed it by putting `EntityDB _db = new EntityDB();` inside the `GetRolesForUser` method. Your suggestion is more elegant :) – jpderooy Feb 09 '12 at 16:32
  • 1
    @jpderooy Don't forget to trap `EntityDB _db = new EntityDB();` it inside the `using` block. You can mark this as the accepted answer. – Eranga Feb 09 '12 at 16:35
2

The problem is a context reference. When you create a reference of the context (EntityDB), out of the method that get the roles from your context, this references still the same, in other words, every data that you select will be the same because the select will be made in the context not in database (this is a way to the EF not be going all the time to the database). The change that you do (in the roles), was made in another context, so to get the right context you have to create a new instance of you context. Do it inside of the method using the keywork using:

using (var database = new EntityDB())
{
    // Get your roles and return them
}
Vinicius Ottoni
  • 4,631
  • 9
  • 42
  • 64