memoryasp.net-mvc-5entity-framework-6asp.net-identity-2user-object

MVC 5 - retrieving the ApplicationUser object


I am developing a MVC 5 internet application and have a question in regards to having a custom object in the ApplicationUser object.

I have a public virtual Account account object in the ApplicationUser object that holds many maximum count variables for objects in my MVC 5 application. This is set for each user when a user registers an account.

Before I create a model object, I check to see if the user has not exceeded their maximum count for the model object. This is done in a service class for the object.

Here is an example of the code used for a file object:

var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
ApplicationUser user = userManager.FindByNameAsync(userName).Result;
int maxFiles = user.account.maxFiles;

I am using many service classes for many objects with similar code to retrieve the ApplicationUser object.

My question is this: Rather than retrieving the ApplicationUser object each time, for each service class, is it possible to store this object when the user logs on, and then refer to this object before a model object is created? If so, where can I store this object for the above purpose?

Also, how much memory/bandwidth is used when retrieving the ApplicationUser object? Is there minimal memory/bandwidth used such that I do not need to worry about memory/bandwidth when retrieving the ApplicationUser object each time before I create a model object?

Thanks in advance.


Solution

  • That is a typical case for adding a claim with a value on logged-in identity.

    When user logs in you add a claim with this value. Value of this claim is then persisted in the cookie. And is available every time user comes back and this is very fast look-up that is happening anyway for cookie authentication.

    To add this claim to the identity, you need to override CreateIdentityAsync method on ApplicationUserManager:

    public override async Task<ClaimsIdentity> CreateIdentityAsync(ApplicationUser user, string authenticationType)
    {
        var identity = await base.CreateIdentityAsync(user, authenticationType);
    
        identity.AddClaim(new Claim("MyApplication:maxFiles", user.account.maxFiles));
    
        return identity;
    }
    

    Then to access this you can create an extension method:

    public static int GetMaxFiles(this IPrincipal principal)
    {
        if (principal == null)
        {
            throw new ArgumentNullException("principal");
        }
    
        var claimsPrincipal = principal as ClaimsPrincipal;
        if (claimsPrincipal == null)
        {
            throw new DomainException("User is not authenticated or IPrincipal is not ClaimsPrincipal");
        }
    
        var claim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "MyApplication:maxFiles");
        int maxfiles = 0;
        if(int.TryParse(claim.Value, out maxfiles))
        {
            return maxfiles;
        }
        throw new Exception("Claim value is not an integer")
    }
    

    And in your application you can use it as var maxFiles = HttpContext.Current.User.GetMaxFiles(). Or if it is a Controller or a View, then you can do var maxFiles = User.GetMaxFiles().

    This is very fast lookup and does not reach into your database.