private async Task <T> GetSecretFromProviderAsync <T>(
            string secretName,
            SecretStoreSource source,
            Func <SecretStoreSource, Task <T> > callRegisteredProvider,
            string eventName) where T : class
        {
            if (_auditingOptions.EmitSecurityEvents)
            {
                _logger.LogSecurityEvent(eventName, new Dictionary <string, object>
                {
                    ["SecretName"]     = secretName,
                    ["SecretProvider"] = source.Options?.Name ?? source.SecretProvider.GetType().Name
                });
            }

            Task <T> resultAsync = callRegisteredProvider(source);

            if (resultAsync is null)
            {
                return(null);
            }

            T result = await resultAsync;

            return(result);
        }
        /// <summary>
        /// Gets the registered named <see cref="ISecretProvider"/> from the secret store.
        /// </summary>
        /// <param name="name">The name that was used to register the <see cref="ISecretProvider"/> in the secret store.</param>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
        /// <exception cref="KeyNotFoundException">
        ///     Thrown when there was no <see cref="ISecretProvider"/> found in the secret store with the given <paramref name="name"/>,
        ///     or there were multiple <see cref="ISecretProvider"/> instances registered with the same name.
        /// </exception>
        public ISecretProvider GetProvider(string name)
        {
            Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to retrieve the registered named secret provider");

            SecretStoreSource source = GetSecretSource(name);

            return(source.SecretProvider);
        }
        /// <summary>
        /// Gets the registered named <see cref="ICachedSecretProvider"/> from the secret store.
        /// </summary>
        /// <param name="name">The name that was used to register the <see cref="ICachedSecretProvider"/> in the secret store.</param>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
        /// <exception cref="KeyNotFoundException">
        ///     Thrown when there was no <see cref="ICachedSecretProvider"/> found in the secret store with the given <paramref name="name"/>,
        ///     or there were multiple <see cref="ICachedSecretProvider"/> instances registered with the same name.
        /// </exception>
        /// <exception cref="NotSupportedException">Thrown when there was an <see cref="ISecretProvider"/> registered but not with caching.</exception>
        public ICachedSecretProvider GetCachedProvider(string name)
        {
            Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to retrieve the registered named secret provider");

            SecretStoreSource source = GetSecretSource(name);

            if (source.CachedSecretProvider is null)
            {
                throw new NotSupportedException(
                          $"Found a registered {nameof(ISecretProvider)} with the name '{name}' in the secret store, but was not configured for caching. "
                          + $"Please use the {nameof(GetProvider)} instead or configure the registered provider with caching");
            }

            return(source.CachedSecretProvider);
        }
        private static IDictionary <string, Lazy <ISecretProvider> > CreateGroupedSecretProviders(
            IEnumerable <SecretStoreSource> secretProviders,
            IEnumerable <CriticalExceptionFilter> criticalExceptionFilters,
            SecretStoreAuditingOptions auditingOptions,
            ILogger <CompositeSecretProvider> logger)
        {
            return(secretProviders
                   .Where(source => source.Options.Name != null)
                   .GroupBy(source => source.Options.Name)
                   .ToDictionary(group => group.Key, group =>
            {
                return new Lazy <ISecretProvider>(() =>
                {
                    if (group.Count() == 1)
                    {
                        SecretStoreSource source = group.First();
                        return source.CachedSecretProvider ?? source.SecretProvider;
                    }

                    return new CompositeSecretProvider(group, criticalExceptionFilters, auditingOptions, logger);
                });
            }));
        }
        private SecretStoreSource GetSecretSource(string name)
        {
            IEnumerable <SecretStoreSource> matchingProviders =
                _secretProviders.Where(provider => provider.Options?.Name == name);

            int count = matchingProviders.Count();

            if (count is 0)
            {
                throw new KeyNotFoundException(
                          $"Could not retrieve the named {nameof(ISecretProvider)} because no provider was registered with the name '{name}'");
            }

            if (count > 1)
            {
                throw new KeyNotFoundException(
                          $"Could not retrieve the named {nameof(ISecretProvider)} because more than one provider was registered with the name '{name}'");
            }

            SecretStoreSource firstProvider = matchingProviders.First();

            return(firstProvider);
        }