tag net mvc asp c# dependency-injection asp.net-core asp.net-core-mvc

c# - mvc - tag helper asp net core 2



ResoluciĆ³n de instancias con ASP.NET Core DI (6)

La interfaz IServiceCollection se usa para construir un contenedor de inyección de dependencia. Una vez que está completamente construido, se compone de una instancia IServiceProvider que puede usar para resolver servicios. Puede inyectar un IServiceProvider en cualquier clase. Las clases IApplicationBuilder y HttpContext pueden proporcionar el proveedor de servicios, a través de las propiedades ApplicationServices o RequestServices respectivamente.

IServiceProvider define un GetService(Type type) para resolver un servicio:

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

También hay varios métodos de extensión de conveniencia disponibles, como serviceProvider.GetService<IFooService>() (agregue un using para Microsoft.Extensions.DependencyInjection ).

Resolviendo servicios dentro de la clase de inicio

Inyectando dependencias

El tiempo de ejecución puede inyectar servicios en el constructor de la clase Startup , como IHostingEnvironment , IConfiguration e IServiceProvider . Tenga en cuenta que este proveedor de servicios es una instancia creada por la capa de alojamiento y contiene solo los servicios para iniciar una aplicación.

Los servicios también se pueden inyectar en el método Configure() . Puede agregar una lista arbitraria de parámetros después del parámetro IApplicationBuilder . También puede inyectar sus propios servicios que están registrados en el método ConfigureServices() aquí, se resolverán desde el proveedor de servicios de aplicaciones en lugar del proveedor de servicios de alojamiento .

public void Configure(IApplicationBuilder app, IFooService fooService) { // ... }

Sin embargo, el método ConfigureServices() no permite inyectar servicios, solo acepta un argumento IServiceCollection . Este es el método donde configura el contenedor de inyección de dependencia de la aplicación. Puede usar los servicios inyectados en el constructor de la startup aquí. Por ejemplo:

public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { // Use Configuration here }

Resolver dependencias manualmente

Si desea resolver servicios manualmente, puede dejar que el tiempo de ejecución inyecte una instancia de IServiceProvider en el constructor o use los ApplicationServices proporcionados por IApplicationBuilder en el método Configure() :

public Startup(IServiceProvider serviceProvider) { var hostingEnv = serviceProvider.GetService<IHostingEnvironment>(); }

o

public void Configure(IApplicationBuilder app) { var serviceProvider = app.ApplicationServices; var hostingEnv = serviceProvider.GetService<IHostingEnvironment>(); }

Sin embargo, si necesita resolver servicios en el método ConfigureServices() , necesita un enfoque diferente. Puede crear un IServiceProvider intermedio a IServiceProvider de una instancia de IServiceCollection que contenga los servicios que están registrados hasta entonces:

public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IFooService, FooService>(); // Build the intermediate service provider var sp = services.BuildServiceProvider(); var fooService = sp.GetService<IFooService>(); }

Necesita el paquete Microsoft.Extensions.DependencyInjection para esto.

Tenga en cuenta:
En general, no debe resolver los servicios dentro del método ConfigureServices() , ya que este es realmente el lugar donde está configurando los servicios de la aplicación. A veces solo necesita acceder a alguna IOptions<MyOptions> . Puede lograr esto vinculando los valores de la instancia de IConfiguration a una instancia de MyOptions (que es esencialmente lo que hace el marco de opciones):

public void ConfigureServices(IServiceCollection services) { var myOptions = new MyOptions(); Configuration.GetSection("SomeSection").Bind(myOptions); }

La resolución manual de servicios (también conocido como Localizador de servicios) en general se conoce como antipatrón . Si bien tiene sus casos de uso (para marcos y / o capas de infraestructura), debe evitarlo tanto como sea posible.

¿Cómo resuelvo manualmente un tipo usando el marco de inyección de dependencia incorporado ASP.NET Core MVC?

Configurar el contenedor es bastante fácil:

public void ConfigureServices(IServiceCollection services) { // ... services.AddTransient<ISomeService, SomeConcreteService>(); }

Pero, ¿cómo puedo resolver ISomeService sin realizar una inyección? Por ejemplo, quiero hacer esto:

ISomeService service = services.Resolve<ISomeService>();

No existen tales métodos en IServiceCollection .


La resolución manual de instancias implica el uso de la interfaz IServiceProvider :

Resolviendo dependencia en Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services) { services.AddTransient<IMyService, MyService>(); var serviceProvider = services.BuildServiceProvider(); var service = serviceProvider.GetService<IMyService>(); }

Resolver dependencias en el inicio.

public void Configure( IApplicationBuilder application, IServiceProvider serviceProvider) { // By type. var service1 = (MyService)serviceProvider.GetService(typeof(MyService)); // Using extension method. var service2 = serviceProvider.GetService<MyService>(); // ... }

Uso de servicios inyectados en tiempo de ejecución

Algunos tipos se pueden inyectar como parámetros de método:

public class Startup { public Startup( IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) { } public void ConfigureServices( IServiceCollection services) { } public void Configure( IApplicationBuilder application, IHostingEnvironment hostingEnvironment, IServiceProvider serviceProvider, ILoggerFactory loggerfactory, IApplicationLifetime applicationLifetime) { } }

Resolver dependencias en acciones del controlador

[HttpGet("/some-action")] public string SomeAction([FromServices] IMyService myService) => "Hello";


Puede inyectar dependencias en atributos como AuthorizeAttribute de esta manera

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));


Si genera una aplicación con una plantilla, tendrá algo como esto en la clase de Startup :

public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddApplicationInsightsTelemetry(Configuration); services.AddMvc(); }

Luego puede agregar dependencias allí, por ejemplo:

services.AddTransient<ITestService, TestService>();

Si desea acceder a ITestService en su controlador, puede agregar IServiceProvider en el constructor y se inyectará:

public HomeController(IServiceProvider serviceProvider)

Luego puede resolver el servicio que agregó:

var service = serviceProvider.GetService<ITestService>();

Tenga en cuenta que para usar la versión genérica debe incluir el espacio de nombres con las extensiones:

using Microsoft.Extensions.DependencyInjection;

ITestService.cs

public interface ITestService { int GenerateRandom(); }

TestService.cs

public class TestService : ITestService { public int GenerateRandom() { return 4; } }

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); services.AddMvc(); services.AddTransient<ITestService, TestService>(); }

HomeController.cs

using Microsoft.Extensions.DependencyInjection; namespace Core.Controllers { public class HomeController : Controller { public HomeController(IServiceProvider serviceProvider) { var service = serviceProvider.GetService<ITestService>(); int rnd = service.GenerateRandom(); }


Si solo necesita resolver una dependencia con el fin de pasarla al constructor de otra dependencia que está registrando, puede hacerlo.

Digamos que tenía un servicio que incluía una cadena y un ISomeService.

public class AnotherService : IAnotherService { public AnotherService(ISomeService someService, string serviceUrl) { ... } }

Cuando vaya a registrar esto dentro de Startup.cs, deberá hacer esto:

services.AddScoped<IAnotherService>(ctx => new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/") );


public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddDbContext<ConfigurationRepository>(options => options.UseSqlServer(Configuration.GetConnectionString("SqlConnectionString"))); services.AddScoped<IConfigurationBL, ConfigurationBL>(); services.AddScoped<IConfigurationRepository, ConfigurationRepository>(); }