question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use IHttpClientFactory in RemoteAuthenticationOptions

See original GitHub issue

Is your feature request related to a problem? Please describe.

ASP.NET Core 2.1 introduced IHttpClientFactory to solve the problems with creating and disposing HttpClient with every call, and the problems with creating a long-lived HttpClient.

However, long-lived HttpClient is still created within the framework. Specifically, in RemoteAuthenticationOptions.Backchannel and RemoteAuthenticationOptions.BackchannelHttpHandler, these have effectively application lifetime because instances of AuthenticationOptions are cached in the singleton IOptionsMonitorCache.

Describe the solution you’d like

Replace RemoteAuthenticationOptions.Backchannel and RemoteAuthenticationOptions.BackchannelHttpHandler with RemoteAuthenticationOptions.BackchannelFactory, so that whenever an HttpClient is needed, it is created from the BackchannelFactory and disposed.

This would also require a new HttpDocumentRetriever constructor that takes an IHttpClientFactory, because JwtBearerPostConfigureOptions, WsFederationPostConfigureOptions and OpenIdConnectPostConfigureOptions initializes a long-lived ConfigurationManager.

Describe alternatives you’ve considered

  • Do not store AuthenticationOptions in IOptionsMonitorCache and make it scoped per request. However, it means that JwtBearer, OpenIdConnect and WsFederation (or 3rd party Saml2 protocol handler) would require fetching metadata on every request, which would slow down every request.

  • Roll my own ConfigurationManager and HttpDocumentRetriever, which would bypass any kind of niceities that .AddJwtBearer, .AddOpenIdConnect extension methods provide.

Additional context

The Grand Auth Redesign of 2017 in Core 2.0 predates IHttpClientFactory in Core 2.1.

In Core 2.0, the new SocketsHttpHandler does not solve DNS problem

Exploring DNS issue

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:4
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
jeffreyrivorcommented, Mar 24, 2020

.NET Core 2.1 introduced SocketsHttpHandler as the default handler, which is designed to be used in a long-lived singleton-like way and can be made to work. In the documentation for alternatives to IHttpClientFactory, it says that setting a finite SocketsHttpHandler.PooledConnectionLifetime solves the stale DNS problem of long-lived handlers while keeping the performance benefits of pooled resource management. The default value for SocketsHttpHandler.PooledConnectionLifetime is Timeout.InfiniteTimeSpan, so default construction of HttpClient or SocketsHttpHandler won’t have the behavior and it has to be manually set.

This should allow us to use an application-lifetime (non-disposed) HttpClient for the Backchannel (or BackchannelHttpHandler) as a workaround.

services.AddAuthentication().AddOpenIdConnect(options =>
{
    // use the handler config
    options.BackchannelHttpHandler = new SocketsHttpHandler
    {
        // recycle pooled sockets every 5 minutes
        PooledConnectionLifetime = TimeSpan.FromMinutes(5),
    };

    // or use the client config
    options.Backchannel = new HttpClient(new SocketsHttpHandler
    {
        PooledConnectionLifetime = TimeSpan.FromMinutes(5),
    }, disposeHandler: false);
});

If you still want to use IHttpClientFactory (it’s got really good delegating handler building overloads) and can work within the fact that the Backchannel will be application-lifetime, you could get fancy with using DI services to configure options.

// configure a named HttpClient for use as the backchannel, use SocketsHttpHandler
// configure delegating handler pipeline like Polly here as usual
services.AddHttpClient("backchannel")
    .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
    {
        PooledConnectionLifetime = TimeSpan.FromMinutes(5),
    });

// configure the options (match the authentication scheme name used in AddOpenIdConnect)
services.AddOptions<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme)
    .Bind(Configuration.GetSection("AzureAD")) // similar trick to AADv2 tutorials for using settings from appsettings.json
    .Configure<IHttpClientFactory>((options, httpClientFactory) =>
    {
        // use the injected IHttpClientFactory to get the named client
        // note: this only happens once (the options are still bound in singleton fashion)
        options.Backchannel = httpClientFactory.CreateClient("backchannel");

        // configure other options here or in the normal AddOpenIdConnect options lambda
    });

// match the authentication scheme used for the options name
services.AddAuthentication()
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { /* configure options here or above with backchannel config */ });
0reactions
damianhcommented, Mar 5, 2020

It’s the expectation that it would resolve the client per request or only at startup? Per request would be challenging for OIDC and JwtBearer due to their use of ConfigManager.

Sorry, I’m not confident enough on this topic to make an assertion.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Use IHttpClientFactory to implement resilient HTTP requests
It's an interface that's used to configure and create HttpClient instances in an app through Dependency Injection (DI). It also provides ...
Read more >
How to use IHttpClientFactory in ASP.NET Core
To create an HttpClient using IHttpClientFactory, you should call the CreateClient method. Once the HttpClient instance is available, you can ...
Read more >
IHttpClientFactory and how to correctly use HttpClient
There are a few ways of using IHttpClientFactory. One is to manually instantiate it in your class and create your client with it....
Read more >
C# Tip: use IHttpClientFactory to generate HttpClient ...
Introducing HttpClientFactory​​ The purpose of IHttpClientFactory is to solve that issue with HttpMessageHandler . An interesting feature of  ...
Read more >
Exploring the code behind IHttpClientFactory in depth
In this post I look in depth at the code behind the default implementation of IHttpClientFactory and see how it manages HttpClient handler ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found