![](/img/trans.png)
[英]Unable to resolve service for type 'System.Net.Http.HttpClient' using DI
[英]Unable to resolve service for type 'System.Net.Http.HttpClient'
我創建了一個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);
}
}
}
我收到此錯誤:
InvalidOperationException:嘗試激活 MyApp.ViewComponents.ProductsViewComponent 時無法解析類型“System.Net.Http.HttpClient”的服務
我以這種方式在Startup
中可用的ConfigureService
方法中注入了HttpClient
:
services.AddHttpClient<FixturesViewComponent>(options =>
{
options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
});
更新:
我也注冊了ProductsViewComponent
,同樣的錯誤。
我有一個類似的問題 - 問題是雙重注冊:
services.AddHttpClient<Service>();
services.AddSingleton<Service>(); // fixed by removing this line
TLDR; ViewComponent
不支持開箱即用的類型化客戶端。 要解決此問題,請在對services.AddMvc(...)
的調用末尾添加對AddViewComponentsAsServices()
的調用。
經過一段很長的聊天,因為能夠重現您的問題,我們最初確定所觀察到的問題是特定於ViewComponent
的。 即使調用IServiceCollection.AddHttpClient<SomeViewComponent>()
,將HttpClient
的實例傳遞給SomeViewComponent
的構造函數也只是拒絕工作。
但是,在SomeComponent
和HttpClient
之間SomeComponent
一個新類 ( SomeService
) 可以按預期工作。 這就是文檔所說的類型化客戶端。 代碼看起來有點像這樣:
// 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)
{
// ...
}
}
正如我已經說過的,這種方法有效 - ASP.NET Core DI 系統非常樂意創建SomeService
的實例及其類型化的HttpClient
實例。
要重述原始問題,請使用以下示例代碼:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<SomeViewComponent>();
// ...
}
public class SomeViewComponent
{
public SomeViewComponent(HttpClient httpClient)
{
// ...
}
}
在這種情況下,由於無法解析HttpClient
,ASP.NET Core DI 系統拒絕創建SomeViewComponent
的實例。 事實證明,這不僅僅適用於ViewComponent
s:它也適用於Controller
s 和TagHelper
s(感謝 Chris Pratt 確認TagHelper
s)。
有趣的是,以下也有效:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<SomeViewComponent>();
// ...
}
public class SomeViewComponent
{
public SomeViewComponent(IHttpClientFactory httpClientFactory)
{
var httpClient = httpClientFactory.CreateClient("SomeViewComponent")
// ...
}
}
在此示例中,我們利用了對AddHttpClient<SomeViewComponent>
的調用為我們注冊了一個命名客戶端的事實。
為了能夠將HttpClient
直接注入到ViewComponent
,我們可以在向 DI 注冊 MVC 時添加對AddViewComponentsAsServices
的調用:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(...)
.AddViewComponentsAsServices();
// ...
}
AddControllersAsServices
和AddTagHelpersAsServices
也可稱為添加了同樣的支持Controller
S和TagHelpers
分別。
如果我們更仔細地查看文檔,很明顯那里的示例都沒有將HttpClient
注入Controller
等 - 根本沒有提到這種方法。
不幸的是,我不知道有足夠的了解ASP.NET的核心DI系統,以便能夠准確解釋為什么這個工作方式是這樣:我上面提供的信息只是解釋了什么一起的解決方案。 Chris Pratt 已在 Github 中打開了一個問題,以便更新文檔以對此進行擴展。
我在Azure Function
版本 2 中遇到了類似的錯誤。根據本文檔,我們應該能夠將IHttpClientFactory
添加為依賴項。 在我的 Azure 函數中添加這個DI
后,我收到了下面提到的錯誤。
Microsoft.Extensions.DependencyInjection.Abstractions:嘗試激活“OServiceBus.Adapter.FetchDataFromSubscription1”時無法解析“System.Net.Http.IHttpClientFactory”類型的服務
問題是我沒有覆蓋 Configure 函數來添加HttpClient
作為注冊的依賴項。 所以我只是在我的 Azure Function 的根目錄中創建了一個名為Statup
的類,如下所示。
使用 Microsoft.Azure.Functions.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();
}
}
}
添加后,我的功能開始正常工作。 希望能幫助到你。
您似乎混淆了兩個視圖組件。 您將FixturesViewComponent
注冊為“命名的 HTTP 客戶端”,但您嘗試在ProductsViewComponent
注入一個HttpClient
實例。
將 HttpClient 注冊更改為ProductsViewComponent
應該會有所幫助:
services.AddHttpClient<ProductsViewComponent>(options =>
{
options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
});
我有一條類似的錯誤消息,試圖將外部 REST 服務的包裝器作為接口注入到我的控制器中。 我需要在 ConfigureServices 中更改以下內容:
services.AddHttpClient<IMyServiceWrapper>("MyServiceWrapper", client =>
{
client.BaseAddress = new Uri("http://some_service/api");
}
到
services.AddHttpClient<IMyServiceWrapper, MyServiceWrapper>("MyServiceWrapper", client =>
{
client.BaseAddress = new Uri("http://some_service/api");
}
為了能夠在我的控制器的構造函數中使用接口:
public MyController(IMyServiceWrapper myService)
{
_myService = myService;
}
用於使用模擬服務測試 myController。
也許它會有所幫助,但在我的情況下這是有效的:
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
{}
}
我也試過services.AddHttpClient<IMyService>()
,由於缺少它的構造函數而無法解決。 還嘗試了services.AddHttpClient<MyService>()
如上所述,但它不會解析配置的實例,如上所述。
所以重要的部分是需要使用用於引用解析類型的類。 所以這也有效:
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
{}
}
這有點道理,但文檔和示例可能會更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.