7

According to examples provided by ASP.NET Core 2.2 documentation in MSDN, it is possible to inject HttpClient to a typed clients (service-classes) by adding the following line to Startup.cs:

// Startup.cs
services.AddHttpClient<GitHubService>();

From controller class it will look like (from now I will use GitHub as a simplification for a domain model):

// GitHubController.cs
public class GitHubController : Controller
{
    private readonly GitHubService _service;
    public GitHubController(GitHubService service)
    {
        _service = service;
    }
}

However, I use MediatR library in my project, so my project structure looks a bit different. I have 2 projects - GitHubFun.Api, GitHubFun.Core - ASP.NET Core 2.2 API project and .NET Core 2.2 class library respectively.

My controller:

// GitHubController.cs
public class GitHubController : Controller
{
    private readonly IMediator _mediator;
    public GitHubController(IMediator mediator)
    {
        _mediator= mediator;
    }

    public async Task<IActionResult> GetGitHubRepositoryInfo(
        GetGitHubRepositoryCommand command)
    {
         _mediator.Send(command);
    }
}

And my handler class:

// GetGitHubRepositoryHandler.cs
public class GetGitHubRepositoryHandler : 
    IRequestHandler<GetGitHubRepositoryCommand , GetGitHubRepositoryCommandResult>
{
    private HttpClient _httpClient;

    public GetGitHubRepositoryHandler(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
}

When I make HTTP request and call an API method, it successfully injects IMediator, but throws an exception on _mediator.Send(command) line.

Exception body:

System.InvalidOperationException: Error constructing handler for request of type MediatR.IRequestHandler`2[IDocs.CryptoServer.Core.Commands.ExtractX509Command,IDocs.CryptoServer.Core.Commands.ExtractX509CommandResult]. Register your handlers with the container. See the samples in GitHub for examples. ---> System.InvalidOperationException: Unable to resolve service for type 'System.Net.Http.HttpClient' while attempting to activate 'IDocs.CryptoServer.Core.Handlers.ExtractX509CommandHandler'

(ExtractX509CommandHandler - is just a real domain model, instead of GetGitHubRepositoryHandler).

It seems that ASP.NET Core DI cannot resolve DI and inject HttpClient to handler.

My Startup.cs has the following lines:

services.AddHttpClient<ExtractX509CommandHandler>();
services.AddMediatR(
       typeof(Startup).Assembly, 
       typeof(ExtractX509CommandHandler).Assembly);
Iskander Raimbaev
  • 1,322
  • 2
  • 17
  • 35
  • 1
    Sounds like it wants you to register the handler itself (i.e. `GetGitHubRepositoryHandler`). Have you done that? – Chris Pratt Mar 18 '19 at 13:31
  • Or actually, it may be an issue with `ExtractX509CommandHander`. Does that take `HttpClient` as dependency? If so, did you register a typed client for that? – Chris Pratt Mar 18 '19 at 13:33
  • @ChrisPratt, yes, I've already registered HttpClient as dependency. And services.AddMediatR( typeof(Startup).Assembly, typeof(ExtractX509CommandHandler).Assembly) encapsulates registration for ExtractX509CommandHandler too. – Iskander Raimbaev Mar 18 '19 at 13:36
  • 1
    No. You misunderstand. If `ExtractX509CommandHandler` takes `HttpClient` as dependency, then you need `services.AddHttpClient()` as well. – Chris Pratt Mar 18 '19 at 13:37
  • @ChrisPratt, yeah, I've already added services.AddHttpClient(). The line services.AddHttpClient() in my question is just a simplification of this class I made for easy understanding. – Iskander Raimbaev Mar 18 '19 at 13:41

2 Answers2

5

I found a solution. For some reasons, in this case we need to pass IHttpClientFactory from Microsoft.Extensions.Http.dll instead of HttpClient to handler class. I just changed one line, it was:

public GetGitHubRepositoryHandler(HttpClient httpClient)

and now:

public GetGitHubRepositoryHandler(IHttpClientFactory httpClientFactory)

and now it works as it should. I don't know why it works, so it will be perfect, if someone could explain what is the difference between injecting IHttpClientFactory and HttpClient to the class.

Iskander Raimbaev
  • 1,322
  • 2
  • 17
  • 35
  • Did you find a reason for this and what the difference is? – Diederik Jan 15 '20 at 13:18
  • AddHttpClient registers your service T at the same time. In this case, AddMediatR also does that, so now you get registrations mixed up. – ESG Oct 30 '20 at 15:54
1

I found a solution.

I'm in ASP.NET Core 3.1.

My handler class :

public class GetProductsListQueryHandler : IRequestHandler<GetProductsListQueryModel, IEnumerable<Product>>
{
    private readonly HttpClient _httpClient;

    public GetProductsListQueryHandler(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

You need to implement your HttpClient in your Startup like this :

services.AddHttpClient<IRequestHandler<GetProductsListQueryModel,IEnumerable<Product>>, GetProductsListQueryHandler>();

And it works! ;)

pdouelle
  • 129
  • 1
  • 5