private Task InitializePersonTypeValueMaps(IdentityValueMaps entry, string personType, string context)
        {
            // Validate Person type
            if (!PersonEntitySpecification.IsPersonEntity(personType))
            {
                throw new ArgumentException(
                          string.Format(
                              "Invalid person type '{0}'. Valid person types are: {1}",
                              personType,
                              "'" + string.Join("','", PersonEntitySpecification.ValidPersonTypes) + "'"));
            }

            // In web application scenarios, copy pertinent context from HttpContext to CallContext
            if (HttpContextStorageTransfer != null)
            {
                HttpContextStorageTransfer.TransferContext();
            }

            var task = InitializePersonTypeValueMapsAsync(entry, personType, context);

            if (task.Status == TaskStatus.Created)
            {
                task.Start();
            }

            return(task);
        }
        private bool TryGetIdentityValueMaps(string personType, string context, out IdentityValueMaps identityValueMaps)
        {
            object personCacheAsObject;

            string cacheKey = GetPersonTypeIdentifiersCacheKey(personType, context);

            if (!_cacheProvider.TryGetCachedObject(cacheKey, out personCacheAsObject))
            {
                // Make sure there is only one cache set being initialized at a time
                lock (_identityValueMapsLock)
                {
                    // Make sure that the entry still doesn't exist yet
                    if (!_cacheProvider.TryGetCachedObject(cacheKey, out personCacheAsObject))
                    {
                        var newValueMaps = new IdentityValueMaps();

                        //Put the initialization task on the cached object so that we know the initialization status by cache entry key
                        //Even if/when the cache provider storage changes context
                        newValueMaps.InitializationTask = InitializePersonTypeValueMaps(newValueMaps, personType, context);

                        //Initial Insert is for while async initialization is running.
                        _cacheProvider.Insert(cacheKey, newValueMaps, DateTime.MaxValue, TimeSpan.FromMinutes(5));

                        _cacheProvider.TryGetCachedObject(cacheKey, out personCacheAsObject);
                    }
                }
            }

            identityValueMaps = personCacheAsObject as IdentityValueMaps;

            if (identityValueMaps == null)
            {
                return(false);
            }

            if (_synchronousInitialization &&
                (identityValueMaps.UniqueIdByUsi == null ||
                 identityValueMaps.UsiByUniqueId == null))
            {
                // Wait for the initialization task to complete
                identityValueMaps.InitializationTask.WaitSafely();

                //If initialization failed, return false.
                if (identityValueMaps.UniqueIdByUsi == null ||
                    identityValueMaps.UsiByUniqueId == null)
                {
                    return(false);
                }

                // With initialization complete, try again (using a single recursive call)
                return(TryGetIdentityValueMaps(personType, context, out identityValueMaps));
            }

            return(true);
        }
        private async Task InitializePersonTypeValueMapsAsync(IdentityValueMaps entry, string personType, string context)
        {
            // Un-handled exceptions here will take down the ASP.NET process
            try
            {
                // Start building the data
                var uniqueIdByUsi = new ConcurrentDictionary <string, string>();
                var usiByUniqueId = new ConcurrentDictionary <string, int>();

                Stopwatch stopwatch = null;

                if (_logger.IsDebugEnabled)
                {
                    stopwatch = new Stopwatch();
                    stopwatch.Start();
                }

                foreach (
                    var valueMap in await _personIdentifiersProvider.GetAllPersonIdentifiers(personType))
                {
                    string key = GetUniqueIdByUsiCacheKey(personType, valueMap.Usi, context);
                    uniqueIdByUsi.TryAdd(key, valueMap.UniqueId);

                    string key2 = GetUsiByUniqueIdCacheKey(personType, valueMap.UniqueId, context);
                    usiByUniqueId.TryAdd(key2, valueMap.Usi);
                }

                if (_logger.IsDebugEnabled)
                {
                    stopwatch.Stop();

                    _logger.DebugFormat(
                        "UniqueId/USI cache for {0} initialized {1:n0} entries in {2:n0} milliseconds.",
                        personType,
                        uniqueIdByUsi.Count,
                        stopwatch.ElapsedMilliseconds);
                }

                entry.SetMaps(usiByUniqueId, uniqueIdByUsi);
                string cacheKey = GetPersonTypeIdentifiersCacheKey(personType, context);

                //Now that it's loaded extend the cache expiration.
                _cacheProvider.Insert(cacheKey, entry, GetAbsoluteExpiration(), _slidingExpiration);
            }
            catch (Exception ex)
            {
                _logger.ErrorFormat(
                    "An exception occurred while trying to warm the PersonCache. UniqueIds will be retrieved individually.\r\n{0}",
                    ex);
            }
        }