¿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 la inyección? Por ejemplo, quiero hacer esto:
ISomeService service = services.Resolve<ISomeService>();
No hay tales métodos en IServiceCollection
.
ConfigureServices()
método (conIServiceCollection
) o en cualquier lugar de la aplicación?Respuestas:
La
IServiceCollection
interfaz se usa para construir un contenedor de inyección de dependencia. Una vez que está completamente construido, se compone de unaIServiceProvider
instancia que puede usar para resolver servicios. Puede inyectar unIServiceProvider
en cualquier clase. LosIApplicationBuilder
yHttpContext
las clases pueden proporcionar el proveedor de servicio, así, a través de susApplicationServices
oRequestServices
propiedades respectivamente.IServiceProvider
define unGetService(Type type)
método para resolver un servicio:También hay varios métodos de extensión de conveniencia disponibles, como
serviceProvider.GetService<IFooService>()
(agregar unusing
paraMicrosoft.Extensions.DependencyInjection
).Resolviendo servicios dentro de la clase de inicio
Inyectando dependencias
Proveedor de alojamiento de servicio del tiempo de ejecución puede inyectar ciertos servicios en el constructor de la
Startup
clase, tales comoIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
en pre-3.0 versiones),ILoggerFactory
yIServiceProvider
. Tenga en cuenta que esta última es una instancia creada por la capa de alojamiento y contiene solo los servicios esenciales para iniciar una aplicación .El
ConfigureServices()
método no permite inyectar servicios, solo acepta unIServiceCollection
argumento. Esto tiene sentido porqueConfigureServices()
es donde registra los servicios requeridos por su aplicación. Sin embargo, puede utilizar los servicios inyectados en el constructor de la startup aquí, por ejemplo:Cualquier servicio registrado en
ConfigureServices()
puede ser inyectado en elConfigure()
método; Puede agregar un número arbitrario de servicios después delIApplicationBuilder
parámetro:Resolver dependencias manualmente
Si necesita resolver los servicios de forma manual, debe utilizar preferiblemente el
ApplicationServices
proporcionado porIApplicationBuilder
en elConfigure()
método:Es posible pasar y usar directamente un
IServiceProvider
en el constructor de suStartup
clase, pero como se indica arriba , contendrá un subconjunto limitado de servicios y, por lo tanto, tiene una utilidad limitada:Si debe resolver los servicios en el
ConfigureServices()
método, se requiere un enfoque diferente. Puede crear un intermediarioIServiceProvider
desde laIServiceCollection
instancia que contiene los servicios que se han registrado hasta ese momento :Tenga en cuenta: en general, debe evitar resolver servicios dentro del
ConfigureServices()
método, ya que este es realmente el lugar donde está configurando los servicios de la aplicación. A veces solo necesitas acceder a unaIOptions<MyOptions>
instancia. Puede lograr esto vinculando los valores de laIConfiguration
instancia a una instancia deMyOptions
(que es esencialmente lo que hace el marco de opciones):La resolución manual de servicios (también conocido como Localizador de servicios) generalmente se considera un antipatrón . Si bien tiene sus casos de uso (para marcos y / o capas de infraestructura), debe evitarlo tanto como sea posible.
fuente
IServiceCollection
inyectado, alguna clase que se está creando manualmente ( fuera del alcance del software intermedio ), un planificador en mi caso, que periódicamente necesita algunos servicios para generar y enviar un correo electrónicoConfigureServices
y ese servicio es un singleton, ¡será un singleton diferente al queController
usa! Supongo que esto se debe a que utiliza una diferenteIServiceProvider
- para evitar esto no se resuelve a través deBuildServiceProvider
y en lugar de mover su operaciones de búsqueda del singleton deConfigureServices
queConfigure(..other params, IServiceProvider serviceProvider)
enStartup.cs
IServiceProvider
instancia diferente , creará una nueva instancia de singleton. Puede evitar esto devolviendo la instancia del proveedor de servicios delConfigureServices
método, de modo que también será el contenedor que usa su aplicación.collection.BuildServiceProvider();
era lo que necesitaba, ¡gracias!La resolución manual de instancias implica el uso de la
IServiceProvider
interfaz:Resolviendo dependencia en Startup.ConfigureServices
Resolver dependencias en el inicio.
Resolver dependencias en el inicio.Configurar en ASP.NET Core 3
Uso de servicios inyectados en tiempo de ejecución
Algunos tipos se pueden inyectar como parámetros de método:
Resolver dependencias en acciones del controlador
fuente
GetService
que es genérico, es un método de extensión en elMicrosoft.Extensions.DependencyInjection
espacio de nombres.Si genera una aplicación con una plantilla, tendrá algo como esto en la
Startup
clase:Luego puede agregar dependencias allí, por ejemplo:
Si desea acceder
ITestService
en su controlador, puede agregarIServiceProvider
el constructor y se inyectará:Luego puede resolver el servicio que agregó:
Tenga en cuenta que para usar la versión genérica debe incluir el espacio de nombres con las extensiones:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
fuente
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.
Cuando vaya a registrar esto dentro de Startup.cs, deberá hacer esto:
fuente
ISomeService
todavía era nulo para mí.Puede inyectar dependencias en atributos como AuthorizeAttribute de esta manera
fuente
Sé que esta es una vieja pregunta, pero me sorprende que no haya un truco bastante obvio y desagradable.
Puede aprovechar la capacidad de definir su propia función de ctor para tomar los valores necesarios de sus servicios a medida que los define ... obviamente, esto se ejecutará cada vez que se solicite el servicio a menos que elimine / borre explícitamente y vuelva a agregar la definición de Este servicio dentro de la primera construcción del ctor explotador .
Este método tiene la ventaja de no requerir que construya el árbol de servicios o que lo use durante la configuración del servicio. Todavía está definiendo cómo se configurarán los servicios.
La forma de arreglar este patrón sería dar
OtherService
una dependencia explícitaIServiceINeedToUse
, en lugar de depender implícitamente de él o del valor de retorno de su método ... o resolver esa dependencia explícitamente de alguna otra manera.fuente
fuente