File: DependencyInjection\PollyServiceCollectionExtensions.cs
Web Access
Project: src\src\HttpClientFactory\Polly\src\Microsoft.Extensions.Http.Polly.csproj (Microsoft.Extensions.Http.Polly)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using Polly.Registry;
using Microsoft.Extensions.DependencyInjection.Extensions;
 
namespace Microsoft.Extensions.DependencyInjection;
 
/// <summary>
/// Provides convenience extension methods to register <see cref="IPolicyRegistry{String}"/> and
/// <see cref="IReadOnlyPolicyRegistry{String}"/> in the service collection.
/// </summary>
public static class PollyServiceCollectionExtensions
{
    /// <summary>
    /// Registers an empty <see cref="PolicyRegistry"/> in the service collection with service types
    /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
     /// <see cref="IConcurrentPolicyRegistry{String}"/> if the service types haven't already been registered
    /// and returns the existing or newly created registry.
    /// </summary>
    /// <param name="services">The <see cref="IServiceCollection"/>.</param>
    /// <returns>The existing or newly created <see cref="IPolicyRegistry{String}"/>.</returns>
    public static IPolicyRegistry<string> AddPolicyRegistry(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }
 
        // Get existing registry or an empty instance
        var registry = services.BuildServiceProvider().GetService<IPolicyRegistry<string>>();
        if (registry == null)
        {
            registry = new PolicyRegistry();
        }
 
        // Try to register for the missing interfaces
        services.TryAddEnumerable(ServiceDescriptor.Singleton<IPolicyRegistry<string>>(registry));
        services.TryAddEnumerable(ServiceDescriptor.Singleton<IReadOnlyPolicyRegistry<string>>(registry));
 
        if (registry is IConcurrentPolicyRegistry<string> concurrentRegistry)
        {
            services.TryAddEnumerable(ServiceDescriptor.Singleton<IConcurrentPolicyRegistry<string>>(concurrentRegistry));
        }
 
        return registry;
    }
 
    /// <summary>
    /// Registers the provided <see cref="IPolicyRegistry{String}"/> in the service collection with service types
    /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
    /// <see cref="IConcurrentPolicyRegistry{String}"/> and returns the provided registry.
    /// </summary>
    /// <param name="services">The <see cref="IServiceCollection"/>.</param>
    /// <param name="registry">The <see cref="IPolicyRegistry{String}"/>.</param>
    /// <returns>The provided <see cref="IPolicyRegistry{String}"/>.</returns>
    public static IPolicyRegistry<string> AddPolicyRegistry(this IServiceCollection services, IPolicyRegistry<string> registry)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }
 
        if (registry == null)
        {
            throw new ArgumentNullException(nameof(registry));
        }
 
        services.AddSingleton<IPolicyRegistry<string>>(registry);
        services.AddSingleton<IReadOnlyPolicyRegistry<string>>(registry);
 
        if (registry is IConcurrentPolicyRegistry<string> concurrentRegistry)
        {
            services.AddSingleton<IConcurrentPolicyRegistry<string>>(concurrentRegistry);
        }
 
        return registry;
    }
 
    /// <summary>
    /// Registers an empty <see cref="PolicyRegistry"/> in the service collection with service types
    /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
    /// <see cref="IConcurrentPolicyRegistry{String}"/> and uses the specified delegate to configure it.
    /// </summary>
    /// <param name="services">The <see cref="IServiceCollection"/>.</param>
    /// <param name="configureRegistry">A delegate that is used to configure an <see cref="IPolicyRegistry{String}"/>.</param>
    /// <returns>The provided <see cref="IServiceCollection"/>.</returns>
    public static IServiceCollection AddPolicyRegistry(this IServiceCollection services, Action<IServiceProvider, IPolicyRegistry<string>> configureRegistry)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }
 
        if (configureRegistry == null)
        {
            throw new ArgumentNullException(nameof(configureRegistry));
        }
 
        // Create an empty registry, configure it and register it as an instance.
        // This is the best way to get a single instance registered using all the interfaces.
        services.AddSingleton(serviceProvider =>
        {
            var registry = new PolicyRegistry();
 
            configureRegistry(serviceProvider, registry);
 
            return registry;
        });
 
        services.AddSingleton<IConcurrentPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
        services.AddSingleton<IPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
        services.AddSingleton<IReadOnlyPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
 
        return services;
    }
}