C# ASP.NET Core 中的 IServiceProvider
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29990618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
IServiceProvider in ASP.NET Core
提问by Sam
I starting to learn changes in ASP.NET 5(vNext) and cannot find how to get IServiceProvider, for example in "Model"'s method
我开始学习 ASP.NET 5(vNext) 中的变化,但找不到如何获取 IServiceProvider,例如在“模型”的方法中
public class Entity
{
public void DoSomething()
{
var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ?
}
}
I know, we configuring services at startup, but where all service collection staying or IServiceProvider?
我知道,我们在启动时配置服务,但是所有服务集合或 IServiceProvider 在哪里?
回答by Anton
Instead of getting your service inline, try injecting it into the constructor.
与其让您的服务内联,不如尝试将其注入到构造函数中。
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
}
}
I also suggest reading up on what AddTransientmeans, as it will have a significant impact on how your application shares instances of DbContext. This is a pattern called Dependency Injection. It takes a while to get used to, but you will never want to go back once you do.
我还建议阅读这AddTransient意味着什么,因为它会对您的应用程序如何共享 DbContext 实例产生重大影响。这是一种称为依赖注入的模式。习惯需要一段时间,但一旦你习惯了,你就再也不想回去了。
回答by Jaime Still
You have to bring in Microsoft.Extensions.DependencyInjectionnamespace to gain access to the generic
您必须引入Microsoft.Extensions.DependencyInjection命名空间才能访问泛型
GetService<T>();
extension method that should be used on
应该使用的扩展方法
IServiceProvider
Also note that you can directly inject services into controllers in ASP.NET 5. See below example.
另请注意,您可以直接将服务注入 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<ISomeService, ServiceImplementation>();
}
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<ISomeService>();
}
Either approach can be used to get access to the service. Additional service extensions for Startup.cs
这两种方法都可用于访问服务。Startup.cs 的附加服务扩展
AddInstance<IService>(new Service())
A single instance is given all the time. You are responsible for initial object creation.
始终给出一个实例。您负责初始对象的创建。
AddSingleton<IService, Service>()
A single instance is created and it acts like a singleton.
创建了一个实例,它的行为就像一个单例。
AddTransient<IService, Service>()
A new instance is created every time it is injected.
每次注入时都会创建一个新实例。
AddScoped<IService, Service>()
A single instance is created inside of the current HTTP Request scope. It is equivalent to Singleton in the current scope context.
在当前 HTTP 请求范围内创建单个实例。它相当于当前作用域上下文中的 Singleton。
Updated 18 October 2018
2018 年 10 月 18 日更新
回答by Serj Sagan
Generally you want to have the DI do its thing and inject that for you:
通常你想让 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();
}
}
However, Entitywould have to be automatically instantiated for you... like a Controlleror a ViewComponent. If you need to manually instantiate this from a place where this dbContextis not available to you, then you can do this:
但是,Entity必须为您自动实例化......就像 aController或 a 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();
}
}
But just to emphasize, this is considered an anti-pattern and should be avoided unless absolutely necessary. And... at the risk of making some pattern people really upset... if all else fails, you can add a static IContainerin a helper class or something and assign it in your StartUpclass in the ConfigureServicesmethod: MyHelper.DIContainer = builder.Build();And this is a really ugly way to do it, but sometimes you just need to get it working.
但只是强调一下,这被认为是一种反模式,除非绝对必要,否则应该避免。而且……冒着让某些模式的人真的不高兴的风险……如果所有其他方法都失败了,您可以static IContainer在辅助类或其他东西中添加 a并将其分配到您的StartUp类中的ConfigureServices方法中:MyHelper.DIContainer = builder.Build();这是一种非常丑陋的方法这样做,但有时你只需要让它工作。
回答by Leonardo Herrera
I don't think it is a good idea for an entity (or a model) to have access to any service.
我认为实体(或模型)访问任何服务都不是一个好主意。
Controllers, on the other hand, do have access to any registered service in their constructors, and you don't have to worry about it.
另一方面,控制器确实可以访问其构造函数中的任何注册服务,您不必担心。
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;
}
}
回答by juFo
use GetRequiredServiceinstead of GetService, like the example on ASP.NET Core tutorials ( https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql)
使用GetRequiredService而不是GetService,就像 ASP.NET Core 教程中的示例 ( https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql)
documentation on the method:
方法文档:
using Microsoft.Extensions.DependencyInjection;
using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
回答by Robert Perry
I think the OP is getting confused. Entities should be as “thin” as possible. They should try not to contain logic, and or external references other than navigation properties. Look up some common patterns like repository pattern which helps to abstract your logic away from the entities themselves
我认为 OP 越来越糊涂了。实体应该尽可能“薄”。它们应该尽量不包含除导航属性之外的逻辑和/或外部引用。查找一些常见模式,例如存储库模式,这有助于将您的逻辑从实体本身中抽象出来
回答by Pit
Do not use GetService()
不使用 GetService()
The difference between GetService and GetRequiredService is related with exception.
GetService 和 GetRequiredService 的区别与异常有关。
GetService() returns null if a service does not exist. GetRequiredService() will throw exception.
如果服务不存在,GetService() 返回 null。GetRequiredService() 将抛出异常。
public static class ServiceProviderServiceExtensions
{
public static T GetService<T>(this IServiceProvider provider)
{
return (T)provider.GetService(typeof(T));
}
public static T GetRequiredService<T>(this IServiceProvider provider)
{
return (T)provider.GetRequiredService(typeof(T));
}
}

