Supondo que eu tenha este registro de serviço:
services.AddScoped<IFoo, Foo>();
Eu sei que você pode " Substituir o registro de serviço no contêiner DI interno do ASP.NET Core? ", mas é possível substituí-lo e ainda manter a instância anterior intacta dessa forma?
services.AddScoped<IFoo>(sp => new MyFooWrapper(/* I need the original Foo here */));
Isso seria útil caso eu estivesse realizando um teste de unidade onde eu pudesse decidir se queria substituir, por exemplo, uma chamada de API externa ou não:
public class MyFooWrapper(IFoo wrapped) : IFoo
{
public void DoSomething()
{
if (TestingWithExternal)
{
wrapped.DoSomething(); // Original method that calls external HTTP API
}
else
{
FakeSomething();
}
}
}
Outro caso de uso é que eu quero encapsular o Blazor, IJSRuntime
já que a MS torna muito difícil mudar seus comportamentos como a implementação é, internal
e reimplementar tudo é muito difícil caso eles atualizem.
Graças à resposta, este é o código que pode substituir vários serviços também
// Replace with fakes
foreach (var s in services.ToList())
{
// Other logic
if (s.ServiceType == typeof(IOaApiService))
{
services.Remove(s);
var implType = s.ImplementationType;
ArgumentNullException.ThrowIfNull(implType);
services.Add(new(implType, implType, s.Lifetime));
services.Add(new(
s.ServiceType,
sp => new FakeOaAiService((IOaApiService)sp.GetRequiredService(implType)),
s.Lifetime));
}
}
Você pode registrar
Foo
o serviço encapsulado como ele mesmo, ou seja:Então, ao registrar a classe wrapper, use
ServiceProvider
para obter a instância registrada:Dessa forma, você substituirá inteiramente tudo
Foo
com seu wrapper. Se você ainda quiser usar ambas as implementações, você tem que separá-las no nível de interface (defineIFooWrapper
) ou usar serviços com chave (mas é o recurso mais recente no .NET).