private static IServiceCollection AddRestClient()

in src/Microsoft.Azure.SignalR.Management/DependencyInjectionExtensions.cs [175:262]


    private static IServiceCollection AddRestClient(this IServiceCollection services)
    {
        // For internal health check. Not impacted by user set timeout.
        services
            .AddHttpClient(Constants.HttpClientNames.InternalDefault, ConfigureProduceInfo)
            .ConfigurePrimaryHttpMessageHandler(ConfigureProxy);

        // Used by user. Impacted by user set timeout.
        services.AddSingleton(sp => sp.GetRequiredService<PayloadBuilderResolver>().GetPayloadContentBuilder())
                .AddSingleton<RestClient>()
                .AddSingleton<IBackOffPolicy>(sp =>
                {
                    var options = sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value;
                    var retryOptions = options.RetryOptions;
                    return retryOptions == null
                        ? new DummyBackOffPolicy()
                        : retryOptions.Mode switch
                        {
                            ServiceManagerRetryMode.Fixed => ActivatorUtilities.CreateInstance<FixedBackOffPolicy>(sp),
                            ServiceManagerRetryMode.Exponential => ActivatorUtilities.CreateInstance<ExponentialBackOffPolicy>(sp),
                            _ => throw new NotSupportedException($"Retry mode {retryOptions.Mode} is not supported.")
                        };
                });
        services
            .AddHttpClient(Constants.HttpClientNames.UserDefault, (sp, client) =>
            {
                ConfigureUserTimeout(sp, client);
                ConfigureProduceInfo(sp, client);
            })
            .ConfigurePrimaryHttpMessageHandler(ConfigureProxy);

        services
            .AddHttpClient(Constants.HttpClientNames.Resilient, (sp, client) =>
            {
                var options = sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value;
                if (options.RetryOptions == null)
                {
                    client.Timeout = options.HttpClientTimeout;
                }
                else
                {
                    // The timeout is enforced by TimeoutHttpMessageHandler.
                    client.Timeout = Timeout.InfiniteTimeSpan;
                }
                ConfigureProduceInfo(sp, client);
                ConfigureMessageTracingId(sp, client);
            })
            .ConfigurePrimaryHttpMessageHandler(ConfigureProxy)
            .AddHttpMessageHandler(sp => ActivatorUtilities.CreateInstance<RetryHttpMessageHandler>(sp, (HttpStatusCode code) => IsTransientErrorForNonMessageApi(code)))
            .AddHttpMessageHandler(sp => ActivatorUtilities.CreateInstance<TimeoutHttpMessageHandler>(sp));

        services
            .AddHttpClient(Constants.HttpClientNames.MessageResilient, (sp, client) =>
            {
                ConfigureUserTimeout(sp, client);
                ConfigureProduceInfo(sp, client);
                ConfigureMessageTracingId(sp, client);
            })
            .ConfigurePrimaryHttpMessageHandler(ConfigureProxy)
            .AddHttpMessageHandler(sp => ActivatorUtilities.CreateInstance<RetryHttpMessageHandler>(sp, (HttpStatusCode code) => IsTransientErrorAndIdempotentForMessageApi(code)));

        return services;

        static HttpMessageHandler ConfigureProxy(IServiceProvider sp) => new HttpClientHandler() { Proxy = sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value.Proxy };

        static bool IsTransientErrorAndIdempotentForMessageApi(HttpStatusCode code) =>
            // Runtime returns 500 for timeout errors too, to avoid duplicate message, we exclude 500 here.
            code > HttpStatusCode.InternalServerError;

        static bool IsTransientErrorForNonMessageApi(HttpStatusCode code) =>
            code >= HttpStatusCode.InternalServerError ||
            code == HttpStatusCode.RequestTimeout;

        static void ConfigureUserTimeout(IServiceProvider sp, HttpClient client) => client.Timeout = sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value.HttpClientTimeout;

        static void ConfigureProduceInfo(IServiceProvider sp, HttpClient client) =>
            client.DefaultRequestHeaders.Add(Constants.AsrsUserAgent, sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value.ProductInfo ??
                // The following value should not be used.
                "Microsoft.Azure.SignalR.Management/");

        static void ConfigureMessageTracingId(IServiceProvider sp, HttpClient client)
        {
            if (sp.GetRequiredService<IOptions<ServiceManagerOptions>>().Value.EnableMessageTracing)
            {
                client.DefaultRequestHeaders.Add(Constants.Headers.AsrsMessageTracingId, MessageWithTracingIdHelper.Generate().ToString(CultureInfo.InvariantCulture));
            }
        }
    }