DryIOC - overriding the transient/scoped registration for a nested scope

217 Views Asked by At

I want to override the transient (or scoped) registration within the (nested) scope. Is this possible? I found I can achieve that with IScope.Use for instances, but how to achieve that for transients?

Consider the situation when you can optionally choose from several customizations, that overrides some feature implementations. The standard implementation is registered within the parent scope, and a nested scope is created for the chosen customization that re-registers the affected interfaces with its own implementations. When different customization is chosen the previous nested scope is disposed and a new one is created with different registrations.

[Test]
public void ScopedTransientDryIOC()
{
    var container = new Container(scopeContext: new AsyncExecutionFlowScopeContext());
    container.Register<IFeature, StandardFeature>(reuse: Reuse.Transient);
    var standardFeature = container.Resolve<IFeature>();
    Assert.That(standardFeature, Is.TypeOf<StandardFeature>(), "In container");

    using (var scope1 = container.OpenScope("scope1"))
    {
       // Without overriding resolves the standard implementation from the parent scope
       var customizedFeature = container.Resolve<IFeature>();
        Assert.That(
            customizedFeature,
            Is.TypeOf<StandardFeature>(),
            "In OpenScope 1st level, before local registration");

        // Such a function does not exists. Is there any workaround?
        scope1.Register<IFeature, CustomizedFeature>(reuse: Reuse.Transient);

        // After overriding it should resolve the customized implementation
        customizedFeature = container.Resolve<IFeature>();
        Assert.That(
            customizedFeature,
            Is.TypeOf<CustomizedFeature>(),
            "In OpenScope 1st level, after local registration");
    }

    // When the overriding scope is disposed resolve again the standard implementation from the root scope
    var standardFeatureClosed = container.Resolve<IFeature>();
    Assert.That(standardFeatureClosed , Is.TypeOf<StandardFeature>(), "After 1st level scope disposed");
}

public interface IFeature {}
public class StandardFeature : IFeature {}
public class CustomizedFeature : IFeature {}



    
1

There are 1 best solutions below

0
dadhi On

The answer is utilizing the Child Container:

            var container = new Container(scopeContext: new AsyncExecutionFlowScopeContext());
            
            container.Register<IFeature, StandardFeature>(reuse: Reuse.Transient);

            var standardFeature = container.Resolve<IFeature>();

            Assert.That(standardFeature, Is.TypeOf<StandardFeature>(), "In container");

            using (var child = container.CreateChild(IfAlreadyRegistered.Replace))
            {
                // Without overriding resolves the standard implementation from the parent scope
                var customizedFeature = container.Resolve<IFeature>();
                Assert.That(
                    customizedFeature,
                    Is.TypeOf<StandardFeature>(),
                    "In OpenScope 1st level, before local registration");

                child.Register<IFeature, CustomizedFeature>(reuse: Reuse.Transient);

                // After overriding it should resolve the customized implementation
                customizedFeature =  child.Resolve<IFeature>();
                Assert.That(
                    customizedFeature,
                    Is.TypeOf<CustomizedFeature>(),
                    "In OpenScope 1st level, after local registration");
            }

            // When the overriding scope is disposed resolve again the standard implementation from the root scope
            var standardFeatureClosed = container.Resolve<IFeature>();
            Assert.That(standardFeatureClosed, Is.TypeOf<StandardFeature>(), "After 1st level scope disposed");