非控制器的网络核心依赖注入
Posted
技术标签:
【中文标题】非控制器的网络核心依赖注入【英文标题】:Net Core Dependency Injection for Non-Controller 【发布时间】:2017-05-27 14:53:17 【问题描述】:这样的事情让我如此头疼,这似乎很疯狂。但这里是:
如何为非控制器类使用 net core 的内置依赖注入?请提供包含实例化的示例。
谢谢。
【问题讨论】:
与使用控制器的方式相同,您将依赖项放在类的构造函数中,然后在 Startup.cs 中连接依赖项。控制器在 DI 方面没有什么特别之处 我们可以查看您当前的注册吗? 查看文档:docs.microsoft.com/en-us/aspnet/core/fundamentals/… @JoeAudette:为了完整起见,Controllers、ViewComponents 和 TagHelpers 在 DI 方面是特殊的,因为默认情况下它们不是由 DI 容器自己解析,而是来自某些工厂。通过调用扩展方法可以改变它。 ***.com/documentation/asp.net-core/1949/… 最值得注意的是使用 3rd 方容器并使用特定类的每个类注入(ClassA 到控制器 A,ClassB 到控制器 B) @Tseng 很有趣!谢谢!我不知道。 【参考方案1】:让课程成为一项服务。
在startup.cs中
services.AddScoped<AccountBusinessLayer>();
然后在控制器中,与其他服务一样:
private readonly AccountBusinessLayer _ABL;
像其他服务一样包含在构造函数中:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,IOptions<IdentityCookieOptions> identityCookieOptions,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
RoleManager<IdentityRole> roleManager,
AccountBusinessLayer ABL
)
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_roleManager = roleManager;
_ABL = ABL;
【讨论】:
在非控制器中试过这个,不起作用。尝试注入其他服务时,AccountBusinessLayer
的 ctor 永远不会运行。
这没有回答问题。
也许我不清楚。使想要使用注入服务的类也成为服务。 Consumer = service => 将其他服务注入到消费服务中。【参考方案2】:
您可以轻松定义具有以下属性的静态类:
public static class StaticServiceProvider
public static IServiceProvider Provider get; set;
在定义类之后,您必须在 Startup.ConfigureServices 方法中范围服务:
public void ConfigureServices(IServiceCollection services)
//TODO: ...
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddSingleton<ISomeInterface, ISomeImplementation>();
然后在启动时的 Startup.Configure 方法中,您可以将提供程序设置为静态类属性:
public void Configure(IApplicationBuilder app, ...)
StaticServiceProvider.Provider = app.ApplicationServices;
//TODO: ...
现在您可以在应用程序中几乎任何地方轻松调用 StaticServiceProvider.Provider.GetService 方法:
var unitOfWork = (IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
【讨论】:
这可以在 .NET 5 隔离应用程序中使用吗?我似乎找不到 IApplicationBuilder。【参考方案3】:我不确定这是最好的答案,但我决定这样做的方法是:
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 同时让库自动连接其他构造函数依赖项。
【讨论】:
【参考方案4】:实际上有很多方法可以注入你的依赖,你会在控制器上找到最常见的一种。还有这个变种
var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));
【讨论】:
以上是关于非控制器的网络核心依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
IOC 控制反转Android 布局依赖注入 ( 布局依赖注入步骤 | 布局依赖注入代码示例 )
IOC 控制反转Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 )
Spring核心思想:IOC(控制反转)DI(依赖注入)和AOP(面向切面编程)