Dependency injection 非控制器的Net内核依赖注入

Dependency injection 非控制器的Net内核依赖注入,dependency-injection,asp.net-core,Dependency Injection,Asp.net Core,像这样的事情让我头疼,这似乎很疯狂。但这是: 对于非控制器类,如何使用NetCore的内置依赖项注入?请提供一个包含实例化的示例 谢谢。我不确定这是不是最好的答案,但我决定这样做的方式是: 1) 根据@SystemCrash建议的@BrunoLM at对这个问题的回答,我创建了一个名为UnderstandingDependencyInjection的新项目,并粘贴在代码示例中 重要提示:除非您访问上面提到的链接(#1),否则我接下来描述的内容将毫无意义。您在下面看到的是一个基于另一个用户在另一个

像这样的事情让我头疼,这似乎很疯狂。但这是:

对于非控制器类,如何使用NetCore的内置依赖项注入?请提供一个包含实例化的示例


谢谢。

我不确定这是不是最好的答案,但我决定这样做的方式是:

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=>将其他服务注入到消费服务中。