[英]Unable to resolve service for type 'System.Net.Http.HttpClient'
I created a ViewComponent
class which call a REST API
using the HttpClient
, this is the code:我创建了一个ViewComponent
类,它使用HttpClient
调用REST API
,这是代码:
public class ProductsViewComponent : ViewComponent
{
private readonly HttpClient _client;
public ProductsViewComponent(HttpClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IViewComponentResult> InvokeAsync(string date)
{
using(var response = await _client.GetAsync($"/product/get_products/{date}"))
{
response.EnsureSuccessStatusCode();
var products = await response.Content.ReadAsAsync<List<Products>>();
return View(products);
}
}
}
I get this error:我收到此错误:
InvalidOperationException: Unable to resolve service for type 'System.Net.Http.HttpClient' while attempting to activate MyApp.ViewComponents.ProductsViewComponent' InvalidOperationException:尝试激活 MyApp.ViewComponents.ProductsViewComponent 时无法解析类型“System.Net.Http.HttpClient”的服务
I injected the HttpClient
in the ConfigureService
method available in Startup
in this way:我以这种方式在Startup
中可用的ConfigureService
方法中注入了HttpClient
:
services.AddHttpClient<FixturesViewComponent>(options =>
{
options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
});
UPDATE:更新:
I registered the ProductsViewComponent
too, same error.我也注册了ProductsViewComponent
,同样的错误。
I had a similar problem - the problem was in double registration:我有一个类似的问题 - 问题是双重注册:
services.AddHttpClient<Service>();
services.AddSingleton<Service>(); // fixed by removing this line
TLDR; TLDR; ViewComponent
s do not support typed clients out of the box. ViewComponent
不支持开箱即用的类型化客户端。 To resolve this, add a call to AddViewComponentsAsServices()
onto the end of the call to services.AddMvc(...)
.要解决此问题,请在对services.AddMvc(...)
的调用末尾添加对AddViewComponentsAsServices()
的调用。
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 ViewComponent
s.经过一段很长的聊天,因为能够重现您的问题,我们最初确定所观察到的问题是特定于ViewComponent
的。 Even with a call to IServiceCollection.AddHttpClient<SomeViewComponent>()
, passing an instance of HttpClient
into SomeViewComponent
s constructor just refused to work.即使调用IServiceCollection.AddHttpClient<SomeViewComponent>()
,将HttpClient
的实例传递给SomeViewComponent
的构造函数也只是拒绝工作。
However, sitting a new class ( SomeService
) between SomeComponent
and HttpClient
works as expected.但是,在SomeComponent
和HttpClient
之间SomeComponent
一个新类 ( SomeService
) 可以按预期工作。 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.正如我已经说过的,这种方法有效 - ASP.NET Core DI 系统非常乐意创建SomeService
的实例及其类型化的HttpClient
实例。
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
.在这种情况下,由于无法解析HttpClient
,ASP.NET Core DI 系统拒绝创建SomeViewComponent
的实例。 It turns out that this is not specific just to ViewComponent
s: it also applies to Controller
s and TagHelper
s (thanks to Chris Pratt for confirming for TagHelper
s).事实证明,这不仅仅适用于ViewComponent
s:它也适用于Controller
s 和TagHelper
s(感谢 Chris Pratt 确认TagHelper
s)。
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.在此示例中,我们利用了对AddHttpClient<SomeViewComponent>
的调用为我们注册了一个命名客户端的事实。
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:为了能够将HttpClient
直接注入到ViewComponent
,我们可以在向 DI 注册 MVC 时添加对AddViewComponentsAsServices
的调用:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(...)
.AddViewComponentsAsServices();
// ...
}
AddControllersAsServices
and AddTagHelpersAsServices
can also be called to add the same support for Controller
s and TagHelpers
respectively. AddControllersAsServices
和AddTagHelpersAsServices
也可称为添加了同样的支持Controller
S和TagHelpers
分别。
If we look at the docs more closely, it's clear that none of the examples there inject a HttpClient
into Controller
s et al - there's simply no mention of this approach at all.如果我们更仔细地查看文档,很明显那里的示例都没有将HttpClient
注入Controller
等 - 根本没有提到这种方法。
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.不幸的是,我不知道有足够的了解ASP.NET的核心DI系统,以便能够准确解释为什么这个工作方式是这样:我上面提供的信息只是解释了什么一起的解决方案。 Chris Pratt has opened an issue in Github for the docs to be updated to expand upon this. Chris Pratt 已在 Github 中打开了一个问题,以便更新文档以对此进行扩展。
I was getting a similar error in my Azure Function
Version 2. As per this document , we should be able to add the IHttpClientFactory
as a dependency.我在Azure Function
版本 2 中遇到了类似的错误。根据本文档,我们应该能够将IHttpClientFactory
添加为依赖项。 After adding this DI
in my Azure Function, I was getting the error mentioned below.在我的 Azure 函数中添加这个DI
后,我收到了下面提到的错误。
Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate 'OServiceBus.Adapter.FetchDataFromSubscription1' Microsoft.Extensions.DependencyInjection.Abstractions:尝试激活“OServiceBus.Adapter.FetchDataFromSubscription1”时无法解析“System.Net.Http.IHttpClientFactory”类型的服务
The issue was that I had not override the Configure function to add the HttpClient
as a registered dependency.问题是我没有覆盖 Configure 函数来添加HttpClient
作为注册的依赖项。 So I just created a class called Statup
in the root directory of my Azure Function as follows.所以我只是在我的 Azure Function 的根目录中创建了一个名为Statup
的类,如下所示。
using Microsoft.Azure.Functions.Extensions.DependencyInjection;使用 Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;使用 Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(ServiceBus.Adapter.Startup))]
namespace ServiceBus.Adapter {
public class Startup: FunctionsStartup {
public override void Configure(IFunctionsHostBuilder builder) {
builder.Services.AddHttpClient();
}
}
}
After adding this, my function started working properly.添加后,我的功能开始正常工作。 Hope it helps.希望能帮助到你。
It seems that you've got two view components mixed up.您似乎混淆了两个视图组件。 You're registering the FixturesViewComponent
as a "named HTTP client" yet you attempt to inject an HttpClient
instance in the ProductsViewComponent
.您将FixturesViewComponent
注册为“命名的 HTTP 客户端”,但您尝试在ProductsViewComponent
注入一个HttpClient
实例。
Changing the HttpClient registration to ProductsViewComponent
should help:将 HttpClient 注册更改为ProductsViewComponent
应该会有所帮助:
services.AddHttpClient<ProductsViewComponent>(options =>
{
options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
});
I had a similar error message trying to inject a wrapper for an external REST service to my controller as an interface.我有一条类似的错误消息,试图将外部 REST 服务的包装器作为接口注入到我的控制器中。 I needed to change the following in ConfigureServices:我需要在 ConfigureServices 中更改以下内容:
services.AddHttpClient<IMyServiceWrapper>("MyServiceWrapper", client =>
{
client.BaseAddress = new Uri("http://some_service/api");
}
to到
services.AddHttpClient<IMyServiceWrapper, MyServiceWrapper>("MyServiceWrapper", client =>
{
client.BaseAddress = new Uri("http://some_service/api");
}
in order to be able to use the interface in the constructor of my controller:为了能够在我的控制器的构造函数中使用接口:
public MyController(IMyServiceWrapper myService)
{
_myService = myService;
}
Useful for testing myController using a mock service.用于使用模拟服务测试 myController。
Maybe it will help, but in my situation this worked:也许它会有所帮助,但在我的情况下这是有效的:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IMyService,MyService>(); // my usual DI injection of a service that can be mocked
services.AddHttpClient<IMyService,MyService>(client => {
client.BaseAddress = new Uri("https://myservice.com/api");
}); // notice that I use IMyService for the reference of the registration AND implementation to where it will be injected.
}
public class MyService
{
public MyService(HttpClient client)
{
// client.BaseAddress is properly set here
}
}
public class MyController : Controller
{
public MyController(IMyService service) // used by the interface
{}
}
I've tried services.AddHttpClient<IMyService>()
as well, which would not resolve due to lack of it's constructor.我也试过services.AddHttpClient<IMyService>()
,由于缺少它的构造函数而无法解决。 Also tried services.AddHttpClient<MyService>()
as above, but it would not resolve the configured instance, as described above.还尝试了services.AddHttpClient<MyService>()
如上所述,但它不会解析配置的实例,如上所述。
So the important part is that class that is used to reference the resolved type needs to be used.所以重要的部分是需要使用用于引用解析类型的类。 So this also works:所以这也有效:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<MyService>(); // registering the type itself, not via interface
services.AddHttpClient<MyService>(client => {
client.BaseAddress = new Uri("https://myservice.com/api");
}); // it's ok here, since it will be resolved by it's own type name
}
public class MyService
{
public MyService(HttpClient client)
{
// client.BaseAddress is properly set here
}
}
public class MyController : Controller
{
public MyController(MyService service) // used by the type directly
{}
}
It kind of makes sense, but documentation and examples could be better.这有点道理,但文档和示例可能会更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.