看起来很疯狂,这样的事情让我很头疼。但这是:
如何为非控制器类使用内核依赖注入网络核心?请提供包含实例化的示例。
感谢。
答案 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框架。
但是,我可能不想/需要创建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。有人会争辩说,这可以让每个控制器和类访问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));