There is need to add new HttpClients to my new APIs when my app is setuped and running. Here is the code from default factory implementation DefatulHttpClientFactory for creating new handler and client:
c#
var entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
var client = new HttpClient(entry.Handler, disposeHandler: false);
Knowing this implementation we can use name that was not registered via
services.AddHttpClient(...) in ConfigureServices(IServiceCollection services) of Startup.
But we still need to configure parameters for returned HttpClient like BaseAddress and Headers. And we can't setup handler lifetime using this way.
My proposal is to add somehow ability to register named clients with the way like services.AddHttpClient(...) but not in ConfigureServices and later.
My first solution was to create decorator for DefaultHttpClientFactory to implement adding actions for httpClient but I still can't set handler lifetime.
I have the same issue I think that new client should be configurable after the DI phase. I'd rather set up my client in the app building phase. it seems just make more sense. (especially if you don't use typed client)
On top of that I have apps that implements webhook pattern so unknown customer at bootstrap will subscribe to my Api. Hence I need to create a new httclient base on that new client. With the current setup it is impossible.
Can you show an example of how you would want to use it?
Here is my naive implementation (and the way I use it):
```c#
public interface ICustomHttpClientFactory : IHttpClientFactory
{
void AddHttpClientAction(string name, Action
}
```c#
public class CustomHttpClientFactory : ICustomHttpClientFactory
{
private readonly ConcurrentDictionary<string, ConcurrentBag<Action<HttpClient>>> _actionsDictionary =
new ConcurrentDictionary<string, ConcurrentBag<Action<HttpClient>>>();
private readonly IHttpClientFactory _httpClientFactory;
public CustomHttpClientFactory(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public HttpClient CreateClient(string name)
{
var client = _httpClientFactory.CreateClient(name);
if (_actionsDictionary.TryGetValue(name, out var actions))
{
foreach (var action in actions)
{
action.Invoke(client);
}
}
return client;
}
public void AddHttpClientAction(string name, Action<HttpClient> configureClient)
{
if (!_actionsDictionary.ContainsKey(name))
_actionsDictionary[name] = new ConcurrentBag<Action<HttpClient>>(new [] {configureClient});
else
_actionsDictionary[name].Add(configureClient);
}
}
```c#
ICustomHttpClientFactory customHttpClientFactory = new CustomHttpClientFactory(...);
customHttpClientFactory.AddHttpClientAction(
httpClient => { httpClient.BaseAddress = new Uri(
var httpClient = customHttpClientFactory.Get(
```
Here I use the fact that distinct "named" handler created in DefaultHttpFactory. But it is created with default lifetime, I can't change this.
Hope this will clear what I want.
I think I need to see a really concrete example to understand what problem you are solving. What are some of the things you're doing with AddHttpClientAction?
It is concrete example for now. I'm registering new _hostAddresses_ via REST API at runtime. And then use httpClients to gather information from this hostAddresses.
With CustomClientFactory I garantee that each obtained httpClient has its own handler.
Moving this to the backlog - I think we should continue the converstation here. I don't really understand why these requirements need to be implemented in this way.
I think my issue has relations with this one https://github.com/aspnet/HttpClientFactory/issues/39.
Let me explain once again: my service use kind of service discovery - it gets list of apis from external source. The cornerstone here is that new APIs can appear in runtime and clients for them should be registered in the factory at that time. Moreover this apis are protected with IdentityServer so my service need to get token for each api it will contact. And now when I register new clients with my workaround I have to invent how to pass token for every call. And it looks ugly at the moment.
Seems to have relevance https://github.com/aspnet/Extensions/issues/932.
I've also run into this same issue, unfortunately I haven't been able to find a nice way of dealing with it.
This can be worked around to some degree with config, as there doesn't seem to be a requirement that your named client needs to be registered at startup. This is a rather primitive example. Naturally if you just want to apply these things across the board then the dictionary is not required.
Registered in startup
services.AddHttpClient();
services.AddSingleton<Dictionary<string, Action<HttpClientFactoryOptions>>>();
services.ConfigureOptions<MyHttpClientFactoryOptions>();
At runtime you just need to ensure that you add the name of the client you're about to create to the dictionary before calling CreateClient.
internal class Other
{
public Other(Dictionary<string, Action<HttpClientFactoryOptions>> options, IHttpClientFactory factory)
{
options.Add("my-client", o => o.HttpClientActions.Add(c => { c.BaseAddress = new Uri("http://example.com"); });
var client = factory.CreateClient("my-client");
}
}
internal class MyHttpClientFactoryOptions : IConfigureNamedOptions<HttpClientFactoryOptions>
{
private readonly Dictionary<string, Action<HttpClientFactoryOptions>> _options;
public MyHttpClientFactoryOptions(Dictionary<string, Action<HttpClientFactoryOptions>> options)
{
_options = options;
}
public void Configure(HttpClientFactoryOptions options)
{
// do nothing
}
public void Configure(string name, HttpClientFactoryOptions options)
{
if (!_options.TryGetValue(name, out var configure))
return;
configure(options);
}
}
Do you have any solutions for such problems(#932 dotnet/runtime#35992 dotnet/extensions#2237 )? @rynowak
Tagging subscribers to this area: @dotnet/ncl
Notify danmosemsft if you want to be subscribed.
Given where we are at in 5.0 and that this API is not yet proposed moving out to 6.0. I think this issue needs more discussion with area-owners (cc @dotnet/ncl). We need to reach concensus on the scenario and then turn this into a formal API proposal.
Most helpful comment
I think my issue has relations with this one https://github.com/aspnet/HttpClientFactory/issues/39.
Let me explain once again: my service use kind of service discovery - it gets list of apis from external source. The cornerstone here is that new APIs can appear in runtime and clients for them should be registered in the factory at that time. Moreover this apis are protected with IdentityServer so my service need to get token for each api it will contact. And now when I register new clients with my workaround I have to invent how to pass token for every call. And it looks ugly at the moment.