Unable to resolve service for type 'System.Net.Http.HttpClient'

TLDR; ViewComponents do not support typed clients out of the box. To resolve this, add a call to AddViewComponentsAsServices() onto the end of the call to services.AddMvc(...).


After a pretty long chat that ran off the back of being able to reproduce your issue, we determined initially that the problem being observed is specific to ViewComponents. Even with a call to IServiceCollection.AddHttpClient<SomeViewComponent>(), passing an instance of HttpClient into SomeViewComponents constructor just refused to work.

However, sitting a new class (SomeService) between SomeComponent and HttpClient works as expected. This is what the docs refer to as a typed client. The code looks a bit like this:

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<SomeService>();
    // ...
}

// SomeService.cs
public class SomeService
{
    public SomeService(HttpClient httpClient)
    {
        // ...
    }
}

// SomeViewComponent.cs
public class SomeViewComponent
{
    public SomeViewComponent(SomeService someService)
    {
        // ...
    }
}

As I've already stated, this approach works - the ASP.NET Core DI system is very happy to create the instance of SomeService and its typed HttpClient instance.

To restate the original problem, take the following example code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<SomeViewComponent>();
    // ...
}

public class SomeViewComponent
{
    public SomeViewComponent(HttpClient httpClient)
    {
        // ...
    }
}

In this case, the ASP.NET Core DI system refuses to create an instance of SomeViewComponent due to not being able to resolve HttpClient. It turns out that this is not specific just to ViewComponents: it also applies to Controllers and TagHelpers (thanks to Chris Pratt for confirming for TagHelpers).

Interestingly, the following also works:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<SomeViewComponent>();
    // ...
}

public class SomeViewComponent
{
    public SomeViewComponent(IHttpClientFactory httpClientFactory)
    {
        var httpClient = httpClientFactory.CreateClient("SomeViewComponent")
        // ...
    }
}

In this example, we're taking advantage of the fact that the call to AddHttpClient<SomeViewComponent> registered a named client for us.

In order to be able to inject HttpClient directly into a ViewComponent, we can add a call to AddViewComponentsAsServices when we register MVC with DI:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(...)
        .AddViewComponentsAsServices();
    // ...
}

AddControllersAsServices and AddTagHelpersAsServices can also be called to add the same support for Controllers and TagHelpers respectively.

If we look at the docs more closely, it's clear that none of the examples there inject a HttpClient into Controllers et al - there's simply no mention of this approach at all.

Unfortunately, I don't know enough about the ASP.NET Core DI system in order to be able to explain exactly why this works the way it does: The information I've provided above simply explains the what along with a solution. Chris Pratt has opened an issue in Github for the docs to be updated to expand upon this.


I had a similar problem - the problem was in double registration:

services.AddHttpClient<Service>();
services.AddSingleton<Service>();  // fixed by removing this line

Similar examples [just adding to clarify that it's not specific to AddSingleton, nor related to the order.]

services.AddScoped<IService, Service>();  // fixed by removing this line
services.AddHttpClient<IService, Service>();