ASP.NET Core中能否包装已注册服务并保留原实例?
如何在替换ASP.NET Core DI服务时保留原实例?
假设我有如下服务注册:
services.AddScoped<IFoo, Foo>();
我知道可以替换ASP.NET Core内置DI容器中的服务注册,但能否在替换时仍保留原实例,实现类似下面的效果?
services.AddScoped<IFoo>(sp => new MyFooWrapper(/* 此处需要原Foo实例 */));
这种需求在单元测试场景中很实用,比如我可以通过控制开关决定是否调用外部API:
public class MyFooWrapper(IFoo wrapped) : IFoo { public void DoSomething() { if (TestingWithExternal) { wrapped.DoSomething(); // 调用外部HTTP API的原方法 } else { FakeSomething(); } } }
另一个场景是包装Blazor的IJSRuntime——由于微软将它的实现设为internal,直接修改行为难度很大,重新实现所有功能又会在版本更新时带来额外的维护负担。
解决方案:批量替换服务并保留原实例
以下是可替换多个服务的实现代码:
// 替换为假实现 foreach (var s in services.ToList()) { // 其他逻辑 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)); } }
内容的提问来源于stack exchange,提问作者Luke Vo
相关产品推荐
相关产品推荐

