private static string BuildEndpointDiscoveryCacheKey(EndpointOperationContextBase context)
        {
            var cacheKeyBuilder = new StringBuilder();

            cacheKeyBuilder.Append(context.CustomerCredentials);
            var identifiers = context.EndpointDiscoveryData.Identifiers;

            if (identifiers != null && identifiers.Count > 0)
            {
                cacheKeyBuilder.Append(string.Format(CultureInfo.InvariantCulture, ".{0}", context.OperationName));
                foreach (var identifier in identifiers)
                {
                    cacheKeyBuilder.Append(string.Format(CultureInfo.InvariantCulture, ".{0}", identifier.Value));
                }
            }

            return(cacheKeyBuilder.ToString());
        }
        /// <summary>
        /// Method that performs endpoint discovery for the current operation
        /// </summary>
        /// <param name="context">Context information used in calculations for endpoint discovery</param>
        /// <param name="InvokeEndpointOperation">The operation to fetch endpoints from the server</param>
        /// <returns></returns>
        public virtual IEnumerable <DiscoveryEndpointBase> ResolveEndpoints(EndpointOperationContextBase context, Func <IList <DiscoveryEndpointBase> > InvokeEndpointOperation)
        {
            //Build the cacheKey
            var cacheKey = BuildEndpointDiscoveryCacheKey(context);

            //Evict cache keys that more than 1 hour old.
            _cache.EvictExpiredLRUListItems(_cacheKeyValidityInSeconds);

            //Check / cleanup the cache
            var refreshCache = false;
            IEnumerable <DiscoveryEndpointBase> endpoints = ProcessEndpointCache(cacheKey, context.EvictCacheKey, context.EvictUri, out refreshCache);

            if (endpoints != null)
            {
                if (refreshCache)
                {
                    //Async fetch new endpoints because one or more of the endpoints in the cache have expired.
#if AWS_ASYNC_API
                    // Task only exists in framework 4.5 and up, and Standard.
                    System.Threading.Tasks.Task.Run(() =>
                    {
                        ProcessInvokeEndpointOperation(cacheKey, InvokeEndpointOperation, false);
                    });
#else
                    // ThreadPool only exists in 3.5 and below. These implementations do not have the Task library.
                    System.Threading.ThreadPool.QueueUserWorkItem((state) =>
                    {
                        ProcessInvokeEndpointOperation(cacheKey, InvokeEndpointOperation, false);
                    });
#endif
                }

                return(endpoints);
            }

            if (context.EvictCacheKey)
            {
                return(null);
            }

            //Determine if we are required to get an endpoint or if we can defer it to an async call
            if (context.EndpointDiscoveryData.Required)
            {
                //Must find an endpoint or error for this operation
                endpoints = ProcessInvokeEndpointOperation(cacheKey, InvokeEndpointOperation, true);
            }
            else if (_config.EndpointDiscoveryEnabled)
            {
                //Optionally find and endpoint for this supported operation async
#if AWS_ASYNC_API
                // Task only exists in framework 4.5 and up, and Standard.
                System.Threading.Tasks.Task.Run(() =>
                {
                    ProcessInvokeEndpointOperation(cacheKey, InvokeEndpointOperation, false);
                });
#else
                // ThreadPool only exists in 3.5 and below. These implementations do not have the Task library.
                System.Threading.ThreadPool.QueueUserWorkItem((state) =>
                {
                    ProcessInvokeEndpointOperation(cacheKey, InvokeEndpointOperation, false);
                });
#endif
                return(null);
            }
            //else not required or endpoint discovery has been disabled so fall through to normal regional endpoint

            return(endpoints);
        }