DI 容器 IServiceProvider:未解析类型的回调
DI Container IServiceProvider: Callback for unresolved types
我正在使用来自 Asp.net Core 的默认 DI 容器,并且我有多个需要嵌套的 IServiceProvider 实例。
我知道默认的 DI 容器本身不支持嵌套,而替代品支持,但如果可能的话我不想切换。
直到现在我只需要解析它的类型,它的依赖项总是在同一个容器中。在这种情况下,我的自滚动表面嵌套 ServiceProvider 可以通过简单地首先检查子容器然后如果在子容器中找不到它则检查父容器来正确解析类型。
但是现在我有一个我想要解析的类型,它在子容器中注册并且依赖于在父容器中注册的类型。
在这种情况下,我的自助解决方案失败了。
所以我想知道是否可以提供一个在 ServiceProvider 无法解析其中一个依赖项时调用的回调。
然后回调将解析类型和 return 所需类型的实例。
有了这个,我可以提供一个回调,它会使用父容器来解析所需的类型。
我想做的事情的一个例子(为简洁起见省略了接口):
public class A { }
public class B { public B(A a) { } }
public class ServiceProviderFallBack {
private ServiceProvider rootServiceProvider;
public ServiceProviderFallBack(ServiceProvider rootServiceProvider) => this.rootServiceProvider = rootServiceProvider;
public object Resolve(Type type) => rootServiceProvider.GetRequiredService(type);
}
public void Run() {
var rootServiceCollection = new ServiceCollection();
rootServiceCollection.AddSingleton<A>();
var rootServiceProvider = rootServiceCollection.BuildServiceProvider();
var webApiServiceCollection = new ServiceCollection();
//How could this be done, if it can be done at all?
webApiServiceCollection.AddSingleton(new ServiceProviderFallBack(rootServiceProvider));
webApiServiceCollection.AddTransient<B>();
var webApiServiceProvider = rootServiceCollection.BuildServiceProvider();
webApiServiceProvider.GetRequiredService<B>();
}
我希望 ServiceProvider webApiServiceProvider
在无法解析类型时使用已注册的类型 ServiceProviderFallBack
并为此使用 ServiceProviderFallBack.Resolve
方法。
该示例已大大简化:ServiceProvider rootServiceCollection
和 webApiServiceProvider
在不同的程序集中。
要回答这个问题,不,目前的实现是不可能的。
看了源码,没办法加回调。
相关部分可以在这里找到:
DependencyInjection/src/DI/ServiceLookup/CallSiteFactory.cs
一旦一个类型被请求,GetCallSite
被调用,它在第一个请求时调用 CreateCallSite
。然后在简单注册的情况下有以下调用链:
CreateCallSite
> TryCreateExact
> TryCreateExact
> CreateConstructorCallSite
> CreateArgumentCallSites
> GetCallSite
> CreateCallSite (If not already cached)
我没有找到可以用自定义 类 替换或可以使用回调的部分。
在那之后没有成功,我发现 OrchardCore/Environment/Shell/Builders/Extensions/ServiceProviderExtensions.cs 可以做我想做的事情,但我遇到了重复注册的问题。
所以我放弃了通用方法并采用了更本地化的方法:
我没有尝试 link 这两个 ServiceProvider,而是将它们分开,只是将必要的服务添加到 "child" ServiceProvider。
我正在使用来自 Asp.net Core 的默认 DI 容器,并且我有多个需要嵌套的 IServiceProvider 实例。
我知道默认的 DI 容器本身不支持嵌套,而替代品支持,但如果可能的话我不想切换。
直到现在我只需要解析它的类型,它的依赖项总是在同一个容器中。在这种情况下,我的自滚动表面嵌套 ServiceProvider 可以通过简单地首先检查子容器然后如果在子容器中找不到它则检查父容器来正确解析类型。 但是现在我有一个我想要解析的类型,它在子容器中注册并且依赖于在父容器中注册的类型。 在这种情况下,我的自助解决方案失败了。
所以我想知道是否可以提供一个在 ServiceProvider 无法解析其中一个依赖项时调用的回调。 然后回调将解析类型和 return 所需类型的实例。
有了这个,我可以提供一个回调,它会使用父容器来解析所需的类型。
我想做的事情的一个例子(为简洁起见省略了接口):
public class A { }
public class B { public B(A a) { } }
public class ServiceProviderFallBack {
private ServiceProvider rootServiceProvider;
public ServiceProviderFallBack(ServiceProvider rootServiceProvider) => this.rootServiceProvider = rootServiceProvider;
public object Resolve(Type type) => rootServiceProvider.GetRequiredService(type);
}
public void Run() {
var rootServiceCollection = new ServiceCollection();
rootServiceCollection.AddSingleton<A>();
var rootServiceProvider = rootServiceCollection.BuildServiceProvider();
var webApiServiceCollection = new ServiceCollection();
//How could this be done, if it can be done at all?
webApiServiceCollection.AddSingleton(new ServiceProviderFallBack(rootServiceProvider));
webApiServiceCollection.AddTransient<B>();
var webApiServiceProvider = rootServiceCollection.BuildServiceProvider();
webApiServiceProvider.GetRequiredService<B>();
}
我希望 ServiceProvider webApiServiceProvider
在无法解析类型时使用已注册的类型 ServiceProviderFallBack
并为此使用 ServiceProviderFallBack.Resolve
方法。
该示例已大大简化:ServiceProvider rootServiceCollection
和 webApiServiceProvider
在不同的程序集中。
要回答这个问题,不,目前的实现是不可能的。
看了源码,没办法加回调。
相关部分可以在这里找到: DependencyInjection/src/DI/ServiceLookup/CallSiteFactory.cs
一旦一个类型被请求,GetCallSite
被调用,它在第一个请求时调用 CreateCallSite
。然后在简单注册的情况下有以下调用链:
CreateCallSite
> TryCreateExact
> TryCreateExact
> CreateConstructorCallSite
> CreateArgumentCallSites
> GetCallSite
> CreateCallSite (If not already cached)
我没有找到可以用自定义 类 替换或可以使用回调的部分。
在那之后没有成功,我发现 OrchardCore/Environment/Shell/Builders/Extensions/ServiceProviderExtensions.cs 可以做我想做的事情,但我遇到了重复注册的问题。
所以我放弃了通用方法并采用了更本地化的方法:
我没有尝试 link 这两个 ServiceProvider,而是将它们分开,只是将必要的服务添加到 "child" ServiceProvider。