问题
I'm creating MVC web application which calls an api using .net core 2.2 using separate HttpClients to call each controller (same api).
Ex:
- For user controller actions : UserService (httpclient)
- For post controller actions : PostService (httpclient)
In startup.cs I use DI as:
services.AddHttpClient<IUserService, UserService>();
services.AddHttpClient<IPostService, PostService>();
In my handler :
public class CommandHandler : IRequestHandler<Command, BaseResponse>
{
private readonly IUserService _userService;
public CommandHandler(IUserService userService)
{
_userService = userService;
}
public Task<BaseResponse> Handle(Command request, CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
But when invoking command handler I get this error:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xxx.Application.Services.Users.UserService' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Net.Http.HttpClient httpClient' of constructor 'Void .ctor(System.Net.Http.HttpClient, xxx.Application.Configurations.IApplicationConfigurations, Microsoft.Extensions.Logging.ILogger`1[xxx.Application.Services.Users.UserService])'.
But I've registered services in autofac module:
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(ServiceModule).Assembly)
.Where(t => t.Namespace.StartsWith("xxx.Application.Services"))
.AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
Here is my UserService class constructor:
public UserService (HttpClient httpClient, IApplicationConfigurations applicationConfig, ILogger<UserService> logger)
{
_httpClient = httpClient;
_applicationConfig = applicationConfig;
_logger = logger;
_remoteServiceBaseUrl = $"{_applicationConfig.WebApiBaseUrl}";
}
I have two questions:
- What does the above error mean?
- Is it good practice to use separate httpclients for different controllers in api?
回答1:
By doing
services.AddHttpClient<IUserService, UserService>();
You will configure the native .net core dependency injection to inject HttpClient to UserService when a IUserService is requested.
Then you do
builder.RegisterAssemblyTypes(typeof(ServiceModule).Assembly)
.Where(t => t.Namespace.StartsWith("xxx.Application.Services"))
.AsImplementedInterfaces().InstancePerLifetimeScope();
which will erase the native dependency injection configuration for IUserService. The IUserService is now registered with UserService without any HttpClient in mind.
The simplest way to add HttpClient would be to register it like this :
builder.Register(c => new HttpClient())
.As<HttpClient>();
or
services.AddHttpClient(); // register the .net core IHttpClientFactory
builder.Register(c => c.Resolve<IHttpClientFactory>().CreateClient())
.As<HttpClient>();
If you want to configure your httpclient for a specific service you can create an autofac module which add parameters like this :
public class HttpClientModule<TService> : Module
{
public HttpClientModule(Action<HttpClient> clientConfigurator)
{
this._clientConfigurator = clientConfigurator;
}
private readonly Action<HttpClient> _clientConfigurator;
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
if (registration.Activator.LimitType == typeof(TService))
{
registration.Preparing += (sender, e) =>
{
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof(HttpClient),
(p, i) => {
HttpClient client = i.Resolve<IHttpClientFactory>().CreateClient();
this._clientConfigurator(client);
return client;
}
)
});
};
}
}
}
Then
builder.RegisterModule(new HttpClientModule<UserService>(client =>
{
client.BaseAddress = new Uri("https://api.XXX.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.XXX.v3+json");
client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-XXX");
}));
来源:https://stackoverflow.com/questions/58791239/how-to-register-typed-httpclient-service-with-autofac