我不确定这是最好的答案,但我决定这样做的方法是:
1) 根据@BrunoLM 在@SystemCrash 建议的这个问题Resolving instances with ASP.NET Core DI 上的回答,我创建了一个名为UnderstandingDependencyInjection 的新项目并粘贴在代码示例中。
重要提示:除非您访问上面引用的链接 (#1),否则我接下来描述的内容将毫无意义。您在下面看到的是一个部分解决方案,它基于另一个用户在另一个 SO 问题中提供的答案。
2) 接下来,我创建了另一个名为 OtherService 的类。我添加了一个依赖于 TestService 的方法 DoSomething()。
3) 在OtherService 的构造函数中,我请求IServiceProvider 以获得ITestService 的具体实现,以便调用它的GenerateRandom() 方法。
4) 回到 HomeController.cs,我只是将 IServiceProvider 引用传递给 OtherService 的构造函数。
所以,这就是我所拥有的:
OtherService.cs
using System;
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class OtherService
{
private readonly ITestService _testService;
public OtherService(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetService<ITestService>();
}
public int DoSomething()
{
var rnd = _testService.GenerateRandom();
return rnd * 2;
}
}
}
HomeController.cs
using Microsoft.Extensions.DependencyInjection;
using UnderstandingDependencyInjection.Services;
namespace UnderstandingDependencyInjection.Controllers
{
public class HomeController : Controller
{
private readonly ITestService _testService;
private readonly IServiceProvider _serviceProvider;
public HomeController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_testService = serviceProvider.GetService<ITestService>();
}
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
var otherService = new OtherService(_serviceProvider);
var rnd = otherService.DoSomething();
ViewBag.RandomNumber = rnd;
return View();
}
因此,总而言之,这项技术的关键是传递控制器接收到的 IServiceProvider 的具体引用......从控制器传递到任何其他自定义类,这些类也需要注册到 ASP 中的任何服务。 NET Core 的 DI 框架。
依赖于 TestService 的静态方法呢?
但是,我可能不想/不需要创建 OtherService 的实例。我可能只想静态调用一个方法,但该方法依赖于由 ASP.NET Core MVC 的依赖注入框架管理的服务。现在呢?
在这种情况下,我能想到的最好的方法是,您需要将 METHOD CALL 的引用传递给静态方法。它看起来很糟糕,我希望有一种更优雅的方式......但这就是我想出来的。
5) 在前面的步骤(以上)的基础上,我添加了一个名为 StaticService 的新类。
6) 我创建了一个以 IServiceProvider 作为参数的方法 DoSomething。
7) 我使用 IServiceProvider 的具体实例来获取 ITestService 的具体实例。我用它来调用 GenerateRandom()。
8) 从控制器调用 StaticService.DoSomething() 方法,将我持有的 IServiceProvider 的具体实例传递给它。
StaticService.cs
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class StaticService
{
// No constructors
public static int DoSomething(IServiceProvider serviceProvider)
{
var testService = serviceProvider.GetService<ITestService>();
var rnd = testService.GenerateRandom();
return rnd * 3;
}
}
}
HomeController.cs
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
//var otherService = new OtherService(_serviceProvider);
//var rnd = otherService.DoSomething();
// What if I need to reference the TestService
// from another service with a STATIC method?
// Best I can tell, you have to pass the
// ServiceProvider in on the method call.
var rnd = StaticService.DoSomething(_serviceProvider);
ViewBag.RandomNumber = rnd;
return View();
}
但是传递 ServiceProvider 不是一种反模式吗?
简而言之,是的。您最终会在代码中到处传递 ServiceProvider。有人会争辩说,这使每个控制器和每个类都可以访问在 ASP.NET Core 的 DI 中注册的每个服务。这是真的,而且看起来很糟糕。
但是你有什么选择呢?是否应该将依赖于您的服务的每个类也定义为服务并在 DI 中注册?换句话说,我应该创建 IOtherService,然后在其构造函数中传递一个具体的 ITestService 吗?
我可以这样做,但是现在我的控制器的构造函数需要 ITestService 和 IOtherService。换句话说,为了正常工作,Controller 需要知道 OtherService 是如何工作的,以及它在内部使用 ITestService 的方式。这似乎也很糟糕。
怎么办?
最佳答案是什么?
坦率地说,我认为最好的答案在这里:
Passing Services using Dependency Injection and Factory Pattern in ASP.NET
@Steven 在他的回答中说:
这确实意味着您可能需要从 ASP.NET Core 的内置 DI 容器转移到功能更丰富的 DI 库,因为内置容器无法进行上下文感知注册ILogger 同时让库自动连接其他构造函数依赖项。