asp.net 无法解析类型"webmaster“的服务

rbl8hiat  于 2023-10-21  发布在  .NET
关注(0)|答案(7)|浏览(133)

我创建了一个ViewComponent类,它使用HttpClient调用REST API,代码如下:

  1. public class ProductsViewComponent : ViewComponent
  2. {
  3. private readonly HttpClient _client;
  4. public ProductsViewComponent(HttpClient client)
  5. {
  6. _client = client ?? throw new ArgumentNullException(nameof(client));
  7. }
  8. public async Task<IViewComponentResult> InvokeAsync(string date)
  9. {
  10. using(var response = await _client.GetAsync($"/product/get_products/{date}"))
  11. {
  12. response.EnsureSuccessStatusCode();
  13. var products = await response.Content.ReadAsAsync<List<Products>>();
  14. return View(products);
  15. }
  16. }
  17. }

我得到这个错误:
InvalidOperationException:在尝试激活MyApp.ViewComponents.ProductsViewComponent时无法解析类型“System.Net.Http.HttpClient”的服务。
我以这种方式将HttpClient注入到Startup中的ConfigureService方法中:

  1. services.AddHttpClient<FixturesViewComponent>(options =>
  2. {
  3. options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
  4. });

更新:
我也注册了ProductsViewComponent,同样的错误。

w41d8nur

w41d8nur1#

我有一个类似的问题-问题是在双重注册:

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

类似的例子[只是添加以澄清它不是特定于AddSingleton,也不是与顺序有关。

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

hmtdttj42#

TLDR;ViewComponent s不支持开箱即用的类型化客户端。要解决这个问题,请在services.AddMvc(...)调用的末尾添加AddViewComponentsAsServices()调用。

经过一个相当长的chat运行的背面能够重现您的问题,我们最初确定,正在观察的问题是特定于ViewComponent的。即使调用了IServiceCollection.AddHttpClient<SomeViewComponent>(),将HttpClient的示例传递到SomeViewComponent的构造函数中也拒绝工作。
但是,在 * SomeComponentHttpClient之间放置一个新类(SomeService)*,就可以正常工作。这就是文档中所说的类型化客户端。代码看起来有点像这样:

  1. // Startup.cs
  2. public void ConfigureServices(IServiceCollection services)
  3. {
  4. services.AddHttpClient<SomeService>();
  5. // ...
  6. }
  7. // SomeService.cs
  8. public class SomeService
  9. {
  10. public SomeService(HttpClient httpClient)
  11. {
  12. // ...
  13. }
  14. }
  15. // SomeViewComponent.cs
  16. public class SomeViewComponent
  17. {
  18. public SomeViewComponent(SomeService someService)
  19. {
  20. // ...
  21. }
  22. }

正如我已经说过的,这种方法是有效的-ASP.NETCoreDI系统非常乐意创建SomeService的示例及其类型化的HttpClient示例。
要重述原始问题,请使用以下示例代码:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddHttpClient<SomeViewComponent>();
  4. // ...
  5. }
  6. public class SomeViewComponent
  7. {
  8. public SomeViewComponent(HttpClient httpClient)
  9. {
  10. // ...
  11. }
  12. }

在这种情况下,ASP.NETCoreDI系统由于无法解析HttpClient而拒绝创建SomeViewComponent的示例。事实证明,这并不特定于ViewComponent s:它也适用于Controller s和TagHelper s(感谢Chris Pratt确认TagHelper s)。
有趣的是,下面的方法也有效:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddHttpClient<SomeViewComponent>();
  4. // ...
  5. }
  6. public class SomeViewComponent
  7. {
  8. public SomeViewComponent(IHttpClientFactory httpClientFactory)
  9. {
  10. var httpClient = httpClientFactory.CreateClient("SomeViewComponent")
  11. // ...
  12. }
  13. }

在本例中,我们利用了对AddHttpClient<SomeViewComponent>的调用为我们注册了一个命名客户端的事实。
为了能够将HttpClient直接注入到ViewComponent中,我们可以在使用DI注册MVC时添加对AddViewComponentsAsServices的调用:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc(...)
  4. .AddViewComponentsAsServices();
  5. // ...
  6. }

也可以调用AddControllersAsServicesAddTagHelpersAsServices分别为Controller s和TagHelpers添加相同的支持。
如果我们更仔细地查看文档,很明显没有一个示例将HttpClient注入到Controller s等人-根本没有提到这种方法。
不幸的是,我对ASP.NET Core DI系统的了解还不够,无法准确解释它的工作方式:我上面提供的信息只是简单地解释了解决方案的沿着内容。Chris Pratt已经在Github上打开了一个issue文档,以便在此基础上进行更新。

展开查看全部
3hvapo4f

3hvapo4f3#

我在Azure Function版本2中遇到了类似的错误。根据this document,我们应该能够添加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;

  1. [assembly: FunctionsStartup(typeof(ServiceBus.Adapter.Startup))]
  2. namespace ServiceBus.Adapter {
  3. public class Startup: FunctionsStartup {
  4. public override void Configure(IFunctionsHostBuilder builder) {
  5. builder.Services.AddHttpClient();
  6. }
  7. }
  8. }

添加此功能后,我的功能开始正常工作。希望有帮助。

5sxhfpxr

5sxhfpxr4#

我在尝试将外部REST服务的 Package 器作为接口注入到我的控制器时也遇到了类似的错误消息。我需要在ConfigureServices中更改以下内容:

  1. services.AddHttpClient<IMyServiceWrapper>("MyServiceWrapper", client =>
  2. {
  3. client.BaseAddress = new Uri("http://some_service/api");
  4. }

  1. services.AddHttpClient<IMyServiceWrapper, MyServiceWrapper>("MyServiceWrapper", client =>
  2. {
  3. client.BaseAddress = new Uri("http://some_service/api");
  4. }

为了能够在我的控制器的构造函数中使用接口:

  1. public MyController(IMyServiceWrapper myService)
  2. {
  3. _myService = myService;
  4. }

使用模拟服务测试myController时非常有用。

展开查看全部
mwngjboj

mwngjboj5#

看起来你把两个视图组件弄混了。您正在将FixturesViewComponent注册为“命名HTTP客户端”,但您试图在ProductsViewComponent中注入HttpClient示例。
将HttpClient注册更改为ProductsViewComponent应该有助于:

  1. services.AddHttpClient<ProductsViewComponent>(options =>
  2. {
  3. options.BaseAddress = new Uri("http://80.350.485.118/api/v2");
  4. });
wb1gzix0

wb1gzix06#

也许这会有帮助,但在我的情况下,这是有效的:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddTransient<IMyService,MyService>(); // my usual DI injection of a service that can be mocked
  4. services.AddHttpClient<IMyService,MyService>(client => {
  5. client.BaseAddress = new Uri("https://myservice.com/api");
  6. }); // notice that I use IMyService for the reference of the registration AND implementation to where it will be injected.
  7. }
  8. public class MyService
  9. {
  10. public MyService(HttpClient client)
  11. {
  12. // client.BaseAddress is properly set here
  13. }
  14. }
  15. public class MyController : Controller
  16. {
  17. public MyController(IMyService service) // used by the interface
  18. {}
  19. }

我也试过services.AddHttpClient<IMyService>(),由于缺少它的构造函数,它无法解决。如上所述,还尝试了services.AddHttpClient<MyService>(),但它无法解析配置的示例。
因此,重要的部分是需要使用用于引用解析类型的类。这也是可行的:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddTransient<MyService>(); // registering the type itself, not via interface
  4. services.AddHttpClient<MyService>(client => {
  5. client.BaseAddress = new Uri("https://myservice.com/api");
  6. }); // it's ok here, since it will be resolved by it's own type name
  7. }
  8. public class MyService
  9. {
  10. public MyService(HttpClient client)
  11. {
  12. // client.BaseAddress is properly set here
  13. }
  14. }
  15. public class MyController : Controller
  16. {
  17. public MyController(MyService service) // used by the type directly
  18. {}
  19. }

这有点道理,但文档和示例可能会更好。

展开查看全部
ht4b089n

ht4b089n7#

对我来说,解决办法是添加:

  1. services.AddHttpClient();

相关问题