net mvc microsoft ihttpcontextaccessor devolvió current controllerbase aspnetcore asp c# dependency-injection asp.net-core

c# - mvc - server mappath asp net core



IServiceProvider en ASP.NET Core (5)

Estoy empezando a aprender los cambios en ASP.NET 5 (vNext) y no puedo encontrar cómo obtener IServiceProvider, por ejemplo en el método de "Modelo"

public class Entity { public void DoSomething() { var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ? } }

Lo sé, configuramos los servicios al inicio, pero ¿dónde se queda la colección de servicios o IServiceProvider?


Debe ingresar Microsoft.Extensions.DependencyInjection espacio de nombres Microsoft.Extensions.DependencyInjection para obtener acceso al genérico.

GetService<T>();

Método de extensión que se debe utilizar en

IServiceProvider

También tenga en cuenta que puede inyectar servicios directamente en los controladores en ASP.NET 5. Consulte el siguiente ejemplo.

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>(); }

Cualquiera de los dos enfoques se puede utilizar para obtener acceso al servicio. Extensiones de servicio adicionales para Startup.cs

AddInstance<IService>(new Service())

Se da una sola instancia todo el tiempo. Usted es responsable de la creación inicial del objeto.

AddSingleton<IService, Service>()

Se crea una sola instancia y actúa como un singleton.

AddTransient<IService, Service>()

Se crea una nueva instancia cada vez que se inyecta.

AddScoped<IService, Service>()

Se crea una instancia única dentro del alcance de la Solicitud HTTP actual. Es equivalente a Singleton en el contexto de alcance actual.

Actualizado el 18 de octubre de 2018

Ver: aspnet GitHub - ServiceCollectionServiceExtensions.cs


En general, quieres que el DI haga su trabajo y se lo inyecte:

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(); } }

Sin embargo, la Entity tendría que crear una instancia automática para usted ... como un Controller o un ViewComponent . Si necesita crear una instancia manual de esto desde un lugar donde este dbContext no está disponible para usted, entonces puede hacer esto:

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(); } }

Pero solo para enfatizar, esto se considera un anti-patrón y debe evitarse a menos que sea absolutamente necesario. Y ... a riesgo de hacer que algunas personas de patrones realmente se enojen ... si todo lo demás falla, puede agregar un static IContainer en una clase auxiliar o algo así y asignarlo en su clase de StartUp en el método ConfigureServices : MyHelper.DIContainer = builder.Build(); Y esta es una manera realmente fea de hacerlo, pero a veces solo necesitas que funcione.


En lugar de obtener su servicio en línea, intente inyectarlo en el 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 } }

También sugiero leer sobre qué significa AddTransient , ya que tendrá un impacto significativo en cómo su aplicación comparte las instancias de DbContext. Este es un patrón llamado inyección de dependencia . Se tarda un poco en acostumbrarse, pero nunca querrá volver una vez que lo haga.


No creo que sea una buena idea que una entidad (o un modelo) tenga acceso a ningún servicio.

Los controladores, por otro lado, tienen acceso a cualquier servicio registrado en sus constructores, y usted no tiene que preocuparse por eso.

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; } }


use GetRequiredService en lugar de GetService , como en el ejemplo de los tutoriales básicos de ASP.NET ( https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql )

Documentación sobre el método:

https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_

using Microsoft.Extensions.DependencyInjection; using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))