-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Describe the bug
When using Microsoft.Extensions.Http AddHttpClient and AddHttpMessageHandler, the instance of T belongs to a different ServiceProvider than the ServiceProvider used to generate a Blazor page - even though T is registered as scoped.
This seems to be a problem with DefaultHttpClientFactory being registered as Singleton instead of Scoped. In Blazor every user connection equates to a Scoped container, so when our Http handling delegates have dependencies we really need them to be created in the correct Scoped container.
The Blazor team suggested this should be reported here. Perhaps we could have the option of registering it scoped or something?
To Reproduce
Create a new Blazor WASM project
Add NuGet reference Microsoft.Extensions.Http
Create a class as follows
public class MyDelegatingHandler : DelegatingHandler
{
private readonly IServiceProvider ServiceProvider;
public MyDelegatingHandler(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("Http service provider hash = " + ServiceProvider.GetHashCode());
return base.SendAsync(request, cancellationToken);
}
}In Program.cs remove the registration of HttpClient and replace it with the following
builder.Services.AddScoped<MyDelegatingHandler>();
builder.Services
.AddHttpClient("local", c => c.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<MyDelegatingHandler>();Edit FetchData.razor
Remove the injection of HttpClient and relace it with
@inject IHttpClientFactory HttpClientFactory
@inject IServiceProvider ServiceProvider
Replace OnInitializedAsync with the following code
protected override async Task OnInitializedAsync()
{
var httpClient = HttpClientFactory.CreateClient("local");
Console.WriteLine("Page service provider hash = " + ServiceProvider.GetHashCode());
forecasts = await httpClient.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}Now run the app, open the console window in the browser, and navigate to the Fetch Data page.
Expected
The hash code for the page and the http delegate should be the same.
Actual
They are different, therefore they are both running within separate IServiceProvider containers.