Como resolver manualmente um tipo usando a estrutura de injeção de dependência interna do ASP.NET Core MVC?
A configuração do contêiner é fácil:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Mas como posso resolver ISomeService
sem executar a injeção? Por exemplo, eu quero fazer isso:
ISomeService service = services.Resolve<ISomeService>();
Não existem tais métodos no IServiceCollection
.
ConfigureServices()
método (withIServiceCollection
) ou em qualquer lugar do aplicativo?Respostas:
A
IServiceCollection
interface é usada para criar um contêiner de injeção de dependência. Depois de totalmente construído, ele é composto por umaIServiceProvider
instância que você pode usar para resolver serviços. Você pode injetar umIServiceProvider
em qualquer classe. As classesIApplicationBuilder
e tambémHttpContext
podem fornecer o provedor de serviços, por meio de suas propriedadesApplicationServices
ouRequestServices
.IServiceProvider
define umGetService(Type type)
método para resolver um serviço:Existem também vários métodos de extensão de conveniência disponíveis, como
serviceProvider.GetService<IFooService>()
(adicione umusing
paraMicrosoft.Extensions.DependencyInjection
).Resolvendo serviços dentro da classe de inicialização
Injetando dependências
Provedor de serviço do tempo de execução pode injetar certos serviços para o construtor da
Startup
classe, tais comoIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
em pré-versões 3.0),ILoggerFactory
eIServiceProvider
. Observe que a última é uma instância criada pela camada de hospedagem e contém apenas os serviços essenciais para iniciar um aplicativo .O
ConfigureServices()
método não permite a injeção de serviços, apenas aceita umIServiceCollection
argumento. Isso faz sentido porqueConfigureServices()
é onde você registra os serviços exigidos pelo seu aplicativo. No entanto, você pode usar serviços injetados no construtor da inicialização aqui, por exemplo:Quaisquer serviços registrados
ConfigureServices()
podem ser injetados noConfigure()
método; você pode adicionar um número arbitrário de serviços após oIApplicationBuilder
parâmetro:Resolução manual de dependências
Se você precisar resolver serviços manualmente, use preferencialmente o
ApplicationServices
fornecido porIApplicationBuilder
noConfigure()
método:É possível passar e usar diretamente um
IServiceProvider
no construtor de suaStartup
classe, mas, como acima, ele conterá um subconjunto limitado de serviços e, portanto, possui utilidade limitada:Se você precisar resolver serviços no
ConfigureServices()
método, será necessária uma abordagem diferente. Você pode criar um intermediário aIServiceProvider
partir daIServiceCollection
instância que contém os serviços que foram registrados até aquele momento :Observação: geralmente você deve evitar resolver serviços dentro do
ConfigureServices()
método, pois esse é realmente o local em que você está configurando os serviços de aplicativo. Às vezes, você só precisa acessar umaIOptions<MyOptions>
instância. Você pode fazer isso vinculando os valores daIConfiguration
instância a uma instância deMyOptions
(que é essencialmente o que a estrutura de opções faz):A resolução manual de serviços (aka Service Locator) é geralmente considerada um antipadrão . Embora tenha seus casos de uso (para estruturas e / ou camadas de infraestrutura), você deve evitá-lo o máximo possível.
fonte
IServiceCollection
injetar, alguma classe que está sendo criada manualmente ( fora do escopo do middle ware ), um agendador no meu caso, que periodicamente precisa de alguns serviços para gerar e envie um email.ConfigureServices
e esse serviço for um singleton, será um singleton diferente daquele que vocêController
usa! Suponho que isso é porque ele usa um diferenteIServiceProvider
- para evitar este não resolverem viaBuildServiceProvider
e, em vez mover o lookup do singleton a partirConfigureServices
deConfigure(..other params, IServiceProvider serviceProvider)
dentroStartup.cs
IServiceProvider
instância diferente, ela criará uma nova instância singleton. Você pode evitar isso retornando a instância do provedor de serviços doConfigureServices
método para que também seja o contêiner que seu aplicativo usa.collection.BuildServiceProvider();
era o que eu precisava, obrigado!A resolução manual de instâncias envolve o uso do método
IServiceProvider
interface:Resolvendo dependência em Startup.ConfigureServices
Resolvendo dependências na inicialização.
Resolvendo dependências no Startup.Configure no ASP.NET Core 3
Usando serviços injetados em tempo de execução
Alguns tipos podem ser injetados como parâmetros de método:
Resolvendo dependências em ações do controlador
fonte
GetService
que é genérico, é um método de extensão noMicrosoft.Extensions.DependencyInjection
espaço para nome.Se você gerar um aplicativo com um modelo, terá algo parecido com isto na
Startup
classe:Você pode adicionar dependências lá, por exemplo:
Se você deseja acessar
ITestService
no seu controlador, você pode adicionarIServiceProvider
o construtor e ele será injetado:Em seguida, você pode resolver o serviço que você adicionou:
Observe que, para usar a versão genérica, é necessário incluir o espaço para nome com as extensões:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
fonte
Se você apenas precisar resolver uma dependência com a finalidade de transmiti-la ao construtor de outra dependência que está registrando, poderá fazer isso.
Digamos que você tenha um serviço que tenha uma string e um ISomeService.
Quando você registrar isso em Startup.cs, precisará fazer o seguinte:
fonte
ISomeService
ainda era nulo para mim.Você pode injetar dependências em atributos como AuthorizeAttribute dessa maneira
fonte
Eu sei que esta é uma pergunta antiga, mas estou surpreso que um hack bastante óbvio e nojento não esteja aqui.
Você pode explorar a capacidade de definir sua própria função de ctor para obter os valores necessários de seus serviços conforme você os define ... obviamente isso seria executado toda vez que o serviço fosse solicitado, a menos que você explicitamente remova / limpe e adicione novamente a definição de este serviço na primeira construção do ctor explorador .
Esse método tem a vantagem de não exigir que você construa a árvore de serviços ou use-a durante a configuração do serviço. Você ainda está definindo como os serviços serão configurados.
A maneira de corrigir esse padrão seria fornecer
OtherService
uma dependência explícitaIServiceINeedToUse
, em vez de depender implicitamente dele ou do valor de retorno do seu método ... ou resolver essa dependência explicitamente de alguma outra maneira.fonte
fonte