Comments (7)
I've seen a similar issue with service activation throwing the same exception, but I'm not sure whether or not that's from using IHttpClientFactory
or not. It's happened probably a handful of times in the last few months. If my memory serves correctly, IOptions<T>
was involved.
That said, looking at your code, using an IEnumerable<T>
all the way through has the potential for performance issues if you have to keep re-walking the enumerator if it's backed by a lazy implementation. I'd suggest materialising it into an IList<T>
near the top of the method using options.ToList()
so that you're operating on a set of a fixed size, and then you can use Count
rather than Count()
and an indexer rather than ElementAt()
.
from httpclientfactory.
@martincostello Thanks for the answer.
I've seen a similar issue with service activation throwing the same exception
I'll have a look at the implementation of IOptions to see what could be wrong with it.
I'd suggest materialising it into an IList
I don't think it would be really different in my case since options is always of type KCAHttpClientOptions[] but, it won't cause any harm so I will follow your suggestion.
from httpclientfactory.
I did try a different implementation of the constructor
internal KCAHttpClients(IServiceCollection services, IEnumerable<IOptions<KCAHttpClientOptions>> options)
and I also did what @martincostello suggested...
try
{
HttpClients = new Dictionary<string, IKCAHttpClient>();
var optList = options.ToList();
....
But the error still happens. As I said before, It's not incredibly frequent, but it happens. The same middleware it's in use in apps deployed in Azure and in IIS 8.5 on-prem. Same random behavior. 🤷♂️
from httpclientfactory.
I would watch out for calling services.BuildServiceProvider()
, you'll build your provider twice, which might be where some of the weirdness is coming from.
Remember that services.AddSingleton(
and other overloads take a func that has the service provider, so try using that it this example.
Something like this maybe:
internal KCAHttpClients(IServiceCollection services, IEnumerable<KCAHttpClientOptions> options)
{
try
{
HttpClients = new Dictionary<string, IKCAHttpClient>();
//https://github.com/aspnet/HttpClientFactory/blob/master/src/Microsoft.Extensions.Http/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs
int optList = options as List<KCAHttpClientOptions> ?? options.ToList();
foreach(var opt in optList)
{
//https://github.com/aspnet/HttpClientFactory/blob/master/src/Microsoft.Extensions.Http/DependencyInjection/HttpClientBuilderExtensions.cs
services.Configure<HttpClientFactoryOptions>(opt.ClientName, httpClientConf => httpClientConf.HttpClientActions.Add((c) =>
{
c.BaseAddress = new Uri(opt.ClientBaseAddress);
if (opt.PermanentHeaders != null)
{
foreach (KCAHeader h in opt.PermanentHeaders)
{
c.DefaultRequestHeaders.Add(h.HeaderKey, h.HeaderValue);
}
}
}));
IKCAHttpClient CreateKCAHttpClient(ServiceProvider sp)
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
var typedClientFactory = sp.GetRequiredService<ITypedHttpClientFactory<KCAHttpClient>>();
var httpClient = httpClientFactory.CreateClient(opt.ClientName);
var client = typedClientFactory.CreateClient(httpClient);
HttpClients.Add(opt.ClientName, client);
return client;
}
if (opt.RequiredToBeSingleton)
{
services.AddSingleton<IKCAHttpClient>(CreateKCAHttpClient);
}
else
{
services.AddTransient<IKCAHttpClient>(CreateKCAHttpClient);
}
}
}
catch (Exception ex)
{
//This is where the "collection changed" error is thrown
Log.Logger.Error("Error during KCAHttpClients initialization!", ex);
throw ex;
}
}
from httpclientfactory.
Sorry I'm not sure I understand what's happening here. What are you trying to accomplish?
from httpclientfactory.
@rynowak Thanks for your reply. Basically, what I wanted to achieve was:
- Having a middleware which can be initialized with options (from 1 to N HttpClients configurations such as base addresses, headers settings, etc... )
- I wanted to have all the HttpClients in the collection created as ITypedHttpClientFactory
So, for example, let's assume a controller needs 3 different HttpClients with the same behavior but different configurations. I'll have the configuration of the middleware in the startup class, then in the controller's constructor signature, I'll only need to include the IClientsCollection and not all the typed clients required and most important I don't have to define different "ITypedClient(s)"
Btw, @slang25 pointed out something which I knew, the reason I was calling services.BuildServiceProvider() was because I couldn't get the required services otherwise and that was because of an error in my original implementation so... I've moved the "services.Configure(...." before initializing the ClientsCollection. I've also realized that for no reason I should have had to add each Client as single service ("services.Add...") since the collection itself has been already added by the time being.
Now my AddService extension looks like this below and everything is working like a charm.
public static IServiceCollection AddKCAHttpClientsTransient(this IServiceCollection services,
IEnumerable<IOptions<KCAHttpClientOptions>> options)
{
services.ConfigureClientFactoryOptions(options);
return services.AddTransient<IKCAHttpClients, KCAHttpClients>(sp =>
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
var typedClientFactory = sp.GetRequiredService<ITypedHttpClientFactory<KCAHttpClient>>();
return new KCAHttpClients(httpClientFactory, typedClientFactory, options);
});
}
You can close the issue, which wasn't an HttpClientFactory issue afterall.
Many thanks.
from httpclientfactory.
Ok, glad you figured it out!
from httpclientfactory.
Related Issues (20)
- How Can I Use ClientCertificates in HttpClientFactory.CreateClient HOT 4
- Getting a endless HttpMessageHandler cleanup cycle HOT 29
- Adding a HttpMessageHandlerType that is registred as Transint in IServiceCollection creates strange results HOT 14
- Microsoft.Extensions.Http.Polly.dll is code signed but Polly.Extensions.Http.dll and Polly.dll are not HOT 4
- Don't capture the ExecutionContext in Timers created for expiry HOT 1
- Asp.net restart: Cannot find method HOT 7
- Error: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate HOT 4
- Test failure: Factory_CleanupCycle_DisposesEligibleHandler HOT 6
- An error occurred while writing to logger(s) HOT 3
- HttpClientFactory Causes High CPU? HOT 33
- Test failure: SuppressScope_False_CreatesNewScope HOT 3
- Running Tests Locally Not Working HOT 4
- In the controller, how do I find the specified type client by name HOT 2
- NullReferenceException in ActiveHandlerTrackingEntry with 2.2.0 preview 3 HOT 8
- Confusing DI behaviour HOT 2
- Remove MessageHandler - Logging Message Handler HOT 5
- Cleanup timer captures logging scopes HOT 3
- Question - HttpMessageHandler access session HOT 2
- Is it possible for HttpClientFactory to target .NET Standard? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from httpclientfactory.