ASP.NET Core中的IServiceProvider
我开始学习ASP.NET 5(vNext)中的更改,但无法找到如何获取IServiceProvider,例如在“Model”的方法中
public class Entity { public void DoSomething() { var dbContext = ServiceContainer.GetService(); //Where is ServiceContainer or something like that ? } }
我知道,我们在启动时配置服务,但所有服务集合停留在哪里或IServiceProvider?
您必须引入Microsoft.Extensions.DependencyInjection
命名空间才能访问generics
GetService();
应该使用的扩展方法
IServiceProvider
另请注意,您可以直接将服务注入ASP.NET 5中的控制器。请参阅下面的示例。
public interface ISomeService { string ServiceValue { get; set; } } public class ServiceImplementation : ISomeService { public ServiceImplementation() { ServiceValue = "Injected from Startup"; } public string ServiceValue { get; set; } }
Startup.cs
public void ConfigureService(IServiceCollection services) { ... services.AddSingleton(); }
HomeController的
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(); }
这两种方法都可用于访问服务。 Startup.cs的附加服务扩展
AddInstance(new Service())
一直有一个实例。 您负责初始对象创建。
AddSingleton()
创建单个实例,它就像一个单例。
AddTransient()
每次注入时都会创建一个新实例。
AddScoped()
在当前HTTP请求范围内创建单个实例。 它等效于当前范围上下文中的Singleton。
2018年10月18日更新
请参阅: aspnet GitHub – ServiceCollectionServiceExtensions.cs
我不认为实体(或模型)访问任何服务是个好主意。
另一方面,控制器可以访问其构造函数中的任何已注册服务,您不必担心它。
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; } }
使用GetRequiredService而不是GetService ,就像ASP.NET核心教程中的示例一样( https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql )
有关方法的文档:
using Microsoft.Extensions.DependencyInjection; using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService>()))
通常你想让DI做它的事情并为你注入:
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(); } }
但是, Entity
必须自动为您实例化…如Controller
或ViewComponent
。 如果需要从无法使用此dbContext
的位置手动实例化,则可以执行以下操作:
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(); } }
但只是要强调,这被认为是反模式,除非绝对必要,否则应该避免。 并且……冒着使某些模式让人感到沮丧的风险……如果所有其他方法都失败了,你可以在一个帮助器类或其他东西中添加一个static IContainer
,并在ConfigureServices
方法的StartUp
类中分配它: MyHelper.DIContainer = builder.Build();
这是一个非常难看的方式,但有时你只需要让它工作。
不要让你的服务内联,尝试将其注入构造函数。
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 } }
我还建议阅读AddTransient
含义,因为它会对您的应用程序如何共享DbContext的实例产生重大影响。 这是一种称为dependency injection的模式。 需要一段时间才能习惯,但是一旦你这样做,你将永远不想回去。