C
C#2mo ago
Ploot

✅ AddHttpClient and AddHostedService

I have a hosted service that I register with my DI as so serviceCollection.AddHostedService<ExampleService>() and everything works fine. However I now need this service to use it's own HttpClient. That seemed like no issue, Just add serviceCollection.AddHttpClient<ExampleService>(x => x.Timeout = Timeout.InfiniteTimeSpan) and I should be good to go, or so I thought.. Everything resolved correctly and the program ran, except for the fact that the injected HttpClient did not in fact have infinite timeout. A quick breakpoint check later and i find that the configuration action isn't triggering, or from what I found online, that client isn't used at all and it's instead falling back to the standard HttpClient that AddHttpClient adds for everything that isn't the targeted type. I found changing my hosted service declaration to serviceCollection.AddHostedService(provider => provider.GetRequiredService<ExampleService>()) resolves these issues but I'm honestly kinda at a loss as to why I had to do this and feel like I must have done something wrong to need to do this. Could anyone enlighten me on the cause of this?
11 Replies
Becquerel
Becquerel2mo ago
when you do AddHttpClient<foobar> you don't put the class you're injecting the http client into as the type argument, right? you define your own http client class and use that as the type args oh, nevermind, after reviewing the docs I see i'm wrong if you inject a IHttpClientFactory into your ExampleService and create a client via string registration, does that work? i.e. serviceCollection.AddHttpClient("foobar", s=> ...), and then clientFactory.CreateClient("foobar")
Becquerel
Becquerel2mo ago
No description
Becquerel
Becquerel2mo ago
just as a sidenote, iirc hosted services are singletons. so this may also be hurting you
Ploot
Ploot2mo ago
This does ^^. Seems a little bit of strange design but hey, it's better than what I had!
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
Ploot
Ploot2mo ago
Sorry, ended up a little busy. This is my min repro code
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Playground;

public static class Program
{
public static async Task Main()
{
IHostBuilder hb = Host.CreateDefaultBuilder();

hb.ConfigureServices((_, serviceCollection) =>
{
//serviceCollection.AddHostedService<TestService>();
serviceCollection.AddHostedService(x => x.GetRequiredService<TestService>());
serviceCollection.AddHttpClient<TestService>(x => x.Timeout = TimeSpan.FromSeconds(30));
});

await hb.Build().StartAsync();
await Task.Delay(-1);
}
}

public class TestService(HttpClient httpClient) : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine(httpClient.Timeout);
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
=> throw new NotImplementedException();
}
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Playground;

public static class Program
{
public static async Task Main()
{
IHostBuilder hb = Host.CreateDefaultBuilder();

hb.ConfigureServices((_, serviceCollection) =>
{
//serviceCollection.AddHostedService<TestService>();
serviceCollection.AddHostedService(x => x.GetRequiredService<TestService>());
serviceCollection.AddHttpClient<TestService>(x => x.Timeout = TimeSpan.FromSeconds(30));
});

await hb.Build().StartAsync();
await Task.Delay(-1);
}
}

public class TestService(HttpClient httpClient) : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine(httpClient.Timeout);
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
=> throw new NotImplementedException();
}
That code is functionally the same as what I'm running and exhibits the same behaviour. The incorrect HttpClient is injected when using the commented out line but works fine with the GetRequiredService method. Idk if I'm expecting something that's incorrect from the DI or if this is weird behaviour :akarishrug:
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
Ploot
Ploot2mo ago
Just how I was taught to do it. I haven't used any of the hosting stuff outside this project so I have little knowledge about it's best practices TLS as in like transport layer security?
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
Ploot
Ploot2mo ago
Ah. Im my actual project I do, this was just from my project i use for testing stuff
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server