如何覆盖不受控制的内部服务类型(使用公共接口)的注入依赖关系?

时间:2019-07-19 03:28:49

标签: asp.net-core dependency-injection

我正在使用具有以下类型的第三方库:

public interface IEngine
{
    ICarburettor Carburettor { get; }

    void VroomVroom();
}

internal class FooEngine : IEngine
{
    public FooEngine(
        ILogger<MerlinEngine> logger,
        ICarburettor carburettor,
        IDistributor distributor,
        IExhaustManifold exhaustManifold
    )
    {
        // ...
    }

    public ICarburettor Carburettor => this.carburettor;

    void VroomVroom()
    {
        // ...
    }
}

使用第三方库中的单个扩展方法IEngine,将FooEngine服务(具有AddFooEngine()实现)添加到ASP.NET Core的服务集合中,该扩展方法还配置了所有其他依赖项(例如ICarburettor等)。该AddFooEngine()具有副作用,因此非常不希望使用私有IServiceBuilder来称呼自己。

通常,我的应用程序将IEngine作为普通的注入服务使用,它使用库自身的ICarburettor实现,但是我需要将FooEngine与单个特定的ICarburettor一起使用只需一个请求即可实现。

我还注意到FooEngine的构造函数还具有已注册的依赖关系-但是它们的接口和实现都是internal,这增加了更多的难度。

所以理想情况下,我想做这样的事情:

public async Task<IActionResult> AControllerAction()
{
    IServiceCollection services = GetExistingSetOfConfiguredServices();
    services.Replace<ICarburettor,MyOwnCarburettor>();
    ServiceProvider tempSP = services.BuildServiceProvider();
    IEngine fooEngine = tempSP.GetRequiredService<IEngine>();

    // Assert that `fooEngine` is still a FooEngine instance, but uses my own carburettor:
    Debug.Assert( fooEngine.GetType().Name == "FooEngine" );
    Debug.Assert( fooEngine.Carburettor.GetType().Name == "MyOwnCarburettor" );

    fooEngine.VroomVroom();
}

但是,,,我不知道该怎么做GetExistingSetOfConfiguredServices()

我知道我可以通过使用ConstructorInfo的缓存FooEngine使用反射并在父类的注入依赖项中转发来解决此问题,但这是一个hack。

不幸的是,到目前为止,我在StackOverflow上看到的所有其他QA都与ConfigureServicesStartup内有关,而在覆盖服务时似乎并没有谈论单关的依赖关系解析单一类型的实现。

0 个答案:

没有答案