非控制器的净核心依赖注入

时间:2017-01-12 13:14:58

标签: dependency-injection asp.net-core

看起来很疯狂,这样的事情让我很头疼。但这是:

如何为非控制器类使用内核依赖注入网络核心?请提供包含实例化的示例。

感谢。

4 个答案:

答案 0 :(得分:5)

只需将课程作为服务。

在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;
}

答案 1 :(得分:2)

我不确定这是最好的答案,但我决定这样做的方法是执行以下操作:

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的依赖注入框架管理的服务。现在怎么办?

在这种情况下,我能想到的最好的,你需要将方法调用的引用传递给静态方法。它看起来很讨厌,我希望有一种更优雅的方式......但这就是我想到的。

5)在前面的步骤(上面)的基础上,我添加了一个名为StaticService的新类。

6)我创建了一个方法DoSomething,它将IServiceProvider作为参数。

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同时使库自动连接其他构造函数依赖项。

答案 2 :(得分:0)

您可以轻松定义具有以下属性的静态类

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));

答案 3 :(得分:0)

实际上有很多方法可以注入依赖,这是在控制器上最常见的方法。还有这个变体

var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));