IServiceProvider in ASP.NET Core
我开始学习ASP.NET 5(vNext)中的更改
并且找不到如何获取IServiceProvider,例如在"模型"的方法中
1 2 3 4 5 6 7 | public class Entity { public void DoSomething() { var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ? } } |
我知道,我们在启动时配置服务,但是所有服务集合仍保留在哪里还是IServiceProvider?
您必须引入
1 | GetService< T >(); |
应在
上使用的扩展方法
1 | IServiceProvider |
还请注意,您可以将服务直接注入ASP.NET 5中的控制器。请参见下面的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public interface ISomeService { string ServiceValue { get; set; } } public class ServiceImplementation : ISomeService { public ServiceImplementation() { ServiceValue ="Injected from Startup"; } public string ServiceValue { get; set; } } |
Startup.cs
1 2 3 4 5 | public void ConfigureService(IServiceCollection services) { ... services.AddSingleton<ISomeService, ServiceImplementation>(); } |
HomeController
1 2 3 4 5 6 7 8 9 10 | using Microsoft.Extensions.DependencyInjection; ... public IServiceProvider Provider { get; set; } public ISomeService InjectedService { get; set; } public HomeController(IServiceProvider provider, ISomeService injectedService) { Provider = provider; InjectedService = Provider.GetService<ISomeService>(); } |
这两种方法均可用于访问服务。 Startup.cs
的其他服务扩展
1 |
始终提供一个实例。您负责初始对象的创建。
1 | AddSingleton<IService, Service>() |
创建一个实例,它的行为就像一个单例。
1 | AddTransient<IService, Service>() |
每次插入新实例都会创建一个实例。
1 | AddScoped<IService, Service>() |
在当前HTTP请求范围内创建一个实例。在当前作用域上下文中等效于Singleton。
2018年10月18日更新
请参阅:aspnet GitHub-ServiceCollectionServiceExtensions.cs
使用GetRequiredService代替GetService,例如ASP.NET Core教程(https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/first-mvc-app/working-with-sql )
方法说明:
https://docs.microsoft.com/zh-cn/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_
1 2 3 | using Microsoft.Extensions.DependencyInjection; using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>())) |
我认为实体(或模型)可以访问任何服务都不是一个好主意。
另一方面,控制器确实可以访问其构造函数中的任何注册服务,而您不必担心。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class NotifyController : Controller { private static IEmailSender emailSender = null; protected static ISessionService session = null; protected static IMyContext dbContext = null; protected static IHostingEnvironment hostingEnvironment = null; public NotifyController( IEmailSender mailSenderService, IMyContext context, IHostingEnvironment env, ISessionService sessionContext) { emailSender = mailSenderService; dbContext = context; hostingEnvironment = env; session = sessionContext; } } |
请勿使用
GetService和GetRequiredService之间的差异与异常有关。
如果服务不存在,
GetService()返回null。
GetRequiredService()将引发异常。
1 2 3 4 5 6 7 8 9 10 11 12 |
我认为OP感到困惑。实体应为" thina"。尽可能。它们应尽量不包含逻辑和/或导航属性以外的外部引用。查找一些常见的模式,例如存储库模式,它可以帮助您将逻辑从实体本身中抽象出来
通常,您想让DI来完成它并为您注入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Entity { private readonly IDataContext dbContext; // The DI will auto inject this for you public class Entity(IDataContext dbContext) { this.dbContext = dbContext; } public void DoSomething() { // dbContext is already populated for you var something = dbContext.Somethings.First(); } } |
但是,必须像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using Microsoft.Extensions.PlatformAbstractions; public class Entity { private readonly IDataContext dbContext; public class Entity() { this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider .GetService(typeof(IDataContext)); } public void DoSomething() { var something = dbContext.Somethings.First(); } } |
但是要强调一点,这被认为是反模式,除非绝对必要,否则应避免使用。并且...冒着使某些模式人员真正沮丧的风险...如果其他所有方法都失败了,则可以在帮助器类中添加
而不是使您的服务内联,请尝试将其注入到构造函数中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient(typeof(DataContext)); } } public class Entity { private DataContext _context; public Entity(DataContext context) { _context = context; } public void DoSomething() { // use _context here } } |
我还建议阅读