Dependency injection 非控制器的Net内核依赖注入
像这样的事情让我头疼,这似乎很疯狂。但这是: 对于非控制器类,如何使用NetCore的内置依赖项注入?请提供一个包含实例化的示例Dependency injection 非控制器的Net内核依赖注入,dependency-injection,asp.net-core,Dependency Injection,Asp.net Core,像这样的事情让我头疼,这似乎很疯狂。但这是: 对于非控制器类,如何使用NetCore的内置依赖项注入?请提供一个包含实例化的示例 谢谢。我不确定这是不是最好的答案,但我决定这样做的方式是: 1) 根据@SystemCrash建议的@BrunoLM at对这个问题的回答,我创建了一个名为UnderstandingDependencyInjection的新项目,并粘贴在代码示例中 重要提示:除非您访问上面提到的链接(#1),否则我接下来描述的内容将毫无意义。您在下面看到的是一个基于另一个用户在另一个
谢谢。我不确定这是不是最好的答案,但我决定这样做的方式是: 1) 根据@SystemCrash建议的@BrunoLM at对这个问题的回答,我创建了一个名为UnderstandingDependencyInjection的新项目,并粘贴在代码示例中 重要提示:除非您访问上面提到的链接(#1),否则我接下来描述的内容将毫无意义。您在下面看到的是一个基于另一个用户在另一个SO问题中提供的答案的部分解决方案。 2) 接下来,我创建了另一个名为OtherService的类。我添加了一个DoSomething()方法,该方法依赖于TestService 3) 在OtherService的构造函数中,我请求IServiceProvider以获得ITestService的具体实现,以便调用其GeneratorAndom()方法 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;
}
}
}
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();
}
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;
}
}
}
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。有人会争辩说,这使每个控制器和类都可以访问ASP.NET核心的DI中注册的每个服务。这是真的,而且看起来很糟糕 但你的选择是什么?每个依赖于您的服务的类是否也应该定义为服务并向DI注册?换句话说,我应该创建IOtherService,然后在其构造函数中传递一个具体的ITestService吗 我可以这样做,但是现在我的控制器的构造函数需要ITestService和IOtherService。换句话说,为了正确工作,控制器需要知道OtherService如何完成其工作,以及它在内部使用ITestService。这似乎也很糟糕 怎么办
最好的答案是什么? 坦率地说,我认为最好的答案是: @史蒂文在回答中说: 但是,这确实意味着您可能需要从ASP.NET Core的内置DI容器转移到功能更丰富的DI库,因为内置容器无法在库自动连接其他构造函数依赖项的同时对ILogger进行上下文感知注册
只需提供a级服务 在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;
}
公共帐户控制器(
用户管理器用户管理器,
SignInManager SignInManager,IOptions标识CookieOptions,
电邮发送者,
伊斯姆森德·斯姆森德,
伊洛格工厂伐木厂,
RoleManager RoleManager,
会计层ABL
)
{
_userManager=userManager;
_signInManager=signInManager;
_externalCookieScheme=identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender=emailSender;
_smsSender=smsSender;
_logger=loggerFactory.CreateLogger();
_roleManager=roleManager;
_ABL=ABL;
}
您可以使用一个属性轻松定义一个静态类,如:
公共静态类StaticServiceProvider
{
公共静态IServiceProvider提供程序{get;set;}
}
定义类后,必须在Startup.ConfigureServices方法中对服务进行作用域:
public void配置服务(IServiceCollection服务)
{
//TODO:。。。
services.addScope();
services.AddSingleton();
}
然后在Startup.Configure方法内部启动时,您可以将提供程序设置为静态类属性:
public void配置(IApplicationBuilder应用程序,…)
{
StaticServiceProvider.Provider=app.ApplicationServices;
//TODO:。。。
}
现在,您可以在应用程序中的几乎所有位置轻松调用StaticServiceProvider.Provider.GetService方法:
var unitOfWork=(IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
实际上有很多方法可以注入依赖关系,这是在控制器上最常见的方法。还有这个变体
var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));
与控制器一样,在类的构造函数中放置依赖项,然后在Startup.cs中连接依赖项。控制器在DICan方面没有什么特别之处,我们看到了您当前的注册?请查看文档:@JoeAudette:为了完整起见,控制器、ViewComponents和TagHelper在DI方面是特别的,因为默认情况下,它们不是由DI容器本身解析的,而是由某些工厂解析的。通过调用扩展方法,可以改变这一点。在使用第三方容器和使用特定类的每类注入(ClassA到控制器A,ClassB到控制器B)时最值得注意@Tseng非常有趣!谢谢我不知道。在非控制器中尝试此操作,不起作用。尝试注入其他服务时,
AccountBusinessLayer
的Ctor从未运行。这并不能回答问题。也许我不清楚。使想要使用注入服务的类也成为服务。Consumer=service=>将其他服务注入到消费服务中。