如何为非控制器类使用Net Core的内置依赖注入?请提供一个包含实例化的示例。
谢谢。
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: ...
}
var unitOfWork = (IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
只需将类作为服务。
在 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;
}
AccountBusinessLayer
的构造函数从未运行。 - Baked InhalfOtherService.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();
}
但是,我可能不想/需要创建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。换句话说,为了正确工作,控制器需要知道OtherService如何完成其工作以及它内部使用ITestService。这似乎也不好。
该怎么办?
坦白地说,我认为最好的答案可以在这里找到:
@Steven在他的回答中说:
这确实意味着您可能需要从ASP.NET Core的内置DI容器转向更具功能的DI库,因为内置容器无法为ILogger进行上下文感知注册,同时自动连接其他构造函数依赖项。
实际上有很多方法可以注入您的依赖项,您会在控制器上找到最常见的一种。还有这个变体
var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));