In C# DI, is it possible to wrap (replace) a registered service with my own but still keep the old instance?
Assuming I have this service registration: services.AddScoped(); I know you can "Replace service registration in ASP.NET Core built-in DI container?" but is it possible to replace it but still keep the former instance intact like this? services.AddScoped(sp => new MyFooWrapper(/* I need the original Foo here */)); This would be helpful in case I am performing a unit test where I can decide if I want to replace, for example, an external API call or not: public class MyFooWrapper(IFoo wrapped) : IFoo { public void DoSomething() { if (TestingWithExternal) { wrapped.DoSomething(); // Original method that calls external HTTP API } else { FakeSomething(); } } } Another use-case is that I want to wrap Blazor's IJSRuntime since MS makes it very difficult to change its behaviors as the implementation is internal and re-implement everything is just very difficult in case they update it. Thanks to the answer, this is the code that can replace multiple services as well // 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)); } }
Assuming I have this service registration:
services.AddScoped();
I know you can "Replace service registration in ASP.NET Core built-in DI container?" but is it possible to replace it but still keep the former instance intact like this?
services.AddScoped(sp => new MyFooWrapper(/* I need the original Foo here */));
This would be helpful in case I am performing a unit test where I can decide if I want to replace, for example, an external API call or not:
public class MyFooWrapper(IFoo wrapped) : IFoo
{
public void DoSomething()
{
if (TestingWithExternal)
{
wrapped.DoSomething(); // Original method that calls external HTTP API
}
else
{
FakeSomething();
}
}
}
Another use-case is that I want to wrap Blazor's IJSRuntime
since MS makes it very difficult to change its behaviors as the implementation is internal
and re-implement everything is just very difficult in case they update it.
Thanks to the answer, this is the code that can replace multiple services as well
// 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));
}
}