Efficient caching of Identity related entities

2019-06-25 14:42发布

问题:

I'm using asp.net MVC5 and asp.net Identity v2 (from the nightly releases) but I think this question still applies to Identity V1.

I have a membership system and i am linking a AspNetUser entity to my membershipuser entity via a field AspUserId in the membershipuser table.

public partial class membershipuser
{
    public int id { get; set; }
    public string full_name { get; set; }
    public string address { get; set; }
    public string AspNetUserId { get; set; }
    .....
}

I was wondering what is the best method of caching your membershipuser record for the life of the request. This way:

public static class extensions
    {
        public static membershipuser GetMember(this System.Security.Principal.IPrincipal User)
        {
            string currentUserId = User.Identity.GetUserId();
            return new MemberEntities().membershipusers.FirstOrDefault(m => m.AspNetUserId == currentUserId );
        }
    }

Or this way:

 public abstract partial class BaseController : Controller
{
    private membershipuser _Member;

    public membershipuser Member
    {
        get { 
            if(_BASRaTMember == null)
            {
               string currentUserId = User.Identity.GetUserId(); 
                BASRaTMember = new BasratEntities().tbl_basrat_members.FirstOrDefault(m => m.AspNetUserId == currentUserId );
            }
            return _BASRaTMember; 
        }
        private set { _BASRaTMember = value; }
    }

}

I'm thinking the Basecontroller method is best as I'm guessing if I called the extension method 5 times to check member properties it would query the database for the user 5 times. Or would it be better to somehow store it against the request? My sole intention is to reduce the database lookups for the requests after the user has been authenticated.

回答1:

So this is less of an issue in 2.0 if you follow the samples pattern of using a single DbContext per request(OwinContext) as the DbContext does this kind of caching itself. But you could explicitly cache users by their UserId as well if you wanted to guarantee this caching irrespective of the specific store caching behavior, you would need to go through some kind of helper method instead of directly using the user manager. The helper would take care of populating the cache, i.e. something like this

public async Task<TUser> GetUser(this IOwinContext context, TKey userId, UserManager<TUser, TKey> manager) {
      var contextKey = "computeYourCacheKey"+userId;
      var user = context.Get<TUser>(contextKey);
      if (user == null) {
          user = await manager.FindByIdAsync(userId);
          context.Set<TUser>(userId, user);
      }
      return user;
}