CCP*_*ony 13 dependency-injection asp.net-core
看起来很疯狂,这样的事情让我很头疼.但这里是:
对于非控制器类,如何为内核使用内置依赖注入?请提供包含实例化的示例.
谢谢.
您可以轻松地使用一个属性定义静态类,例如:
public static class StaticServiceProvider
{
public static IServiceProvider Provider { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
定义类后,您必须在 Startup.ConfigureServices 方法中确定服务的范围:
public void ConfigureServices(IServiceCollection services)
{
//TODO: ...
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddSingleton<ISomeInterface, ISomeImplementation>();
}
Run Code Online (Sandbox Code Playgroud)
然后在启动时的 Startup.Configure 方法中,您可以将提供程序设置为静态类属性:
public void Configure(IApplicationBuilder app, ...)
{
StaticServiceProvider.Provider = app.ApplicationServices;
//TODO: ...
}
Run Code Online (Sandbox Code Playgroud)
现在,您几乎可以在应用程序中的任何位置轻松调用 StaticServiceProvider.Provider.GetService 方法:
var unitOfWork = (IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
Run Code Online (Sandbox Code Playgroud)
小智 7
只需将课程作为服务即可。
在startup.cs中
services.AddScoped<AccountBusinessLayer>();
Run Code Online (Sandbox Code Playgroud)
然后在控制器中,与对其他服务的操作相同:
private readonly AccountBusinessLayer _ABL;
Run Code Online (Sandbox Code Playgroud)
与其他服务一样,包含在构造函数中:
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;
}
Run Code Online (Sandbox Code Playgroud)
我不确定这是最好的答案,但我决定这样做的方法是执行以下操作:
1)根据@BrunoLM 在这个问题Resolving instances with ASP.NET Core DI由@SystemCrash 建议的答案,我创建了一个名为UnderstandingDependencyInjection 的新项目并粘贴到代码示例中。
重要提示:除非您访问上面引用的链接(#1),否则我接下来描述的内容将没有意义。您在下面看到的是一个部分解决方案,它基于另一个用户在另一个 SO 问题中提供的答案。
2) 接下来,我创建了另一个名为 OtherService 的类。我添加了一个依赖于 TestService 的方法 DoSomething()。
3) 在OtherService 的构造函数中,我请求IServiceProvider 以获得ITestService 的具体实现,以便我可以调用它的GenerateRandom() 方法。
4) 回到 HomeController.cs,我只是将 IServiceProvider 引用传递给 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
家庭控制器.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();
}
Run Code Online (Sandbox Code Playgroud)
所以,总而言之,这项技术的关键是传递控制器接收到的 IServiceProvider 的具体引用......从控制器传递到任何其他自定义类,这些自定义类也需要注册到 ASP.NET Core DI 中的任何服务框架。
但是,我可能不想/不需要创建 OtherService 的实例。我可能只想静态调用一个方法,但该方法依赖于由 ASP.NET Core MVC 的依赖注入框架管理的服务。现在怎么办?
在这种情况下,我能想出的最好方法是,您需要将 ON THE METHOD CALL 的引用传递给静态方法。它看起来很糟糕,我希望有一种更优雅的方式......但这是我想出来的。
5) 在前面的步骤(上面)的基础上,我添加了一个名为 StaticService 的新类。
6) 我创建了一个以 IServiceProvider 作为参数的 DoSomething 方法。
7) 我使用 IServiceProvider 的具体实例来获取 ITestService 的具体实例。我用它来调用 GenerateRandom()。
8) 从控制器中,调用 StaticService.DoSomething() 方法,将我持有的 IServiceProvider 的具体实例传递给它。
静态服务.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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
家庭控制器.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();
}
Run Code Online (Sandbox Code Playgroud)
简而言之,是的。您最终会在代码中到处传递 ServiceProvider。有些人会争辩说,这使每个控制器和类都可以访问在 ASP.NET Core 的 DI 中注册的每个服务。这是真的,而且看起来很糟糕。
但是你有什么选择?每个依赖于您的服务的类是否也应该定义为服务并在 DI 中注册?换句话说,我应该创建 IOtherService,然后在其构造函数中传递一个具体的 ITestService 吗?
我可以做到这一点,但是现在我的控制器的构造函数需要 ITestService 和 IOtherService。换句话说,为了正常工作,Controller 需要知道 OtherService 如何完成它的工作以及它在内部使用 ITestService。这似乎也很糟糕。
该怎么办?
坦率地说,我认为最好的答案在这里:
@Steven 在他的回答中说:
然而,这确实意味着您可能需要从 ASP.NET Core 的内置 DI 容器转移到功能更丰富的 DI 库,因为内置容器无法为 ILogger 进行上下文感知注册,同时具有该库还会自动连接其他构造函数依赖项。
| 归档时间: |
|
| 查看次数: |
6272 次 |
| 最近记录: |