protected virtual void Dispose(bool disposing)
        {
            if (_extraAuthDbContextOptions != null && _context != null)
            {
                if (disposing)
                {
                    _context.Dispose();
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.
                _context = null;
            }
        }
        /// <summary>
        /// This will set up the user's feature permissions if either of the following states are found
        /// - The current claims doesn't have the PackedPermissionClaimType. This happens when someone logs in.
        /// - If the LastPermissionsUpdatedClaimType is missing (null) or is a lower number that is stored in the TimeStore cache.
        /// It will also add a HierarchicalKeyClaimName claim with the user's data key if not present.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ValidateAsync(CookieValidatePrincipalContext context)
        {
            var extraContext = new ExtraAuthorizeDbContext(_extraAuthContextOptions, _authChanges);
            //now we set up the lazy values - I used Lazy for performance reasons, as 99.9% of the time the lazy parts aren't needed
            // ReSharper disable once AccessToDisposedClosure
            var rtoPLazy = new Lazy <CalcAllowedPermissions>(() => new CalcAllowedPermissions(extraContext));
            // ReSharper disable once AccessToDisposedClosure
            var dataKeyLazy = new Lazy <CalcDataKey>(() => new CalcDataKey(extraContext));

            var originalClaims = context.Principal.Claims.ToList();
            var impHandler     = new ImpersonationHandler(context.HttpContext, _protectionProvider, originalClaims);

            var newClaims = new List <Claim>();

            if (originalClaims.All(x => x.Type != PermissionConstants.PackedPermissionClaimType) ||
                impHandler.ImpersonationChange ||
                _authChanges.IsOutOfDateOrMissing(AuthChangesConsts.FeatureCacheKey,
                                                  originalClaims.SingleOrDefault(x => x.Type == PermissionConstants.LastPermissionsUpdatedClaimType)?.Value,
                                                  extraContext))
            {
                //Handle the feature permissions
                var userId = impHandler.GetUserIdForWorkingOutPermissions();
                newClaims.AddRange(await BuildFeatureClaimsAsync(userId, rtoPLazy.Value));
            }

            if (originalClaims.All(x => x.Type != DataAuthConstants.HierarchicalKeyClaimName) ||
                impHandler.ImpersonationChange)
            {
                var userId = impHandler.GetUserIdForWorkingDataKey();
                newClaims.AddRange(BuildDataClaims(userId, dataKeyLazy.Value));
            }

            if (newClaims.Any())
            {
                //Something has changed so we replace the current ClaimsPrincipal with a new one

                newClaims.AddRange(RemoveUpdatedClaimsFromOriginalClaims(originalClaims, newClaims)); //Copy over unchanged claims
                impHandler.AddOrRemoveImpersonationClaim(newClaims);
                //Build a new ClaimsPrincipal and use it to replace the current ClaimsPrincipal
                var identity     = new ClaimsIdentity(newClaims, "Cookie");
                var newPrincipal = new ClaimsPrincipal(identity);
                context.ReplacePrincipal(newPrincipal);
                //THIS IS IMPORTANT: This updates the cookie, otherwise this calc will be done every HTTP request
                context.ShouldRenew = true;
            }
            extraContext.Dispose(); //be tidy and dispose the context.
        }