Search code examples
c#inversion-of-controlunity-container

Inject string parameter with specific value to all types


Given

interface IFoo ...
class MyClass1 : IFoo
{
    public MyClass1(string id) ...
}

class MyClass2 : IFoo
{
    public MyClass2(string id) ...
}
//new classes will be added

When I resolve the classes:

UnityContainer container = ...;
container.Resolve(typeThatImplementsIFoo);

Then how can I setup UnityContainer so that it injects value "123" to any ctor parameter "string id" when resolving any class that implements IFoo?


Solution

  • You can do that if you write a custom BuilderStrategy that will override input parameter in constructor for your classes.

    I wrote a test classes for simplifying. They are the similar to your classes:

        public interface IFoo {}
    
        public class MyClass : IFoo
        {
            public string Id;
    
            public MyClass(string id)
            {
                Id = id;
            }
        }
    
        public class MyClass2 : IFoo
        {
            public string Id;
    
            public MyClass2(string id)
            {
                Id = id;
            }
        }
    

    They are the custom BuilderStrategy and the custom UnityContainerExtension:

        public class UnityExtension<TInterface> : UnityContainerExtension
        {
            private readonly string _paramName;
            private readonly object _paramValue;
    
            public UnityExtension(string paramName, object paramValue)
            {
                _paramName = paramName;
                _paramValue = paramValue;
            }
    
            protected override void Initialize()
            {
                var strategy = new BuildStrategy<TInterface>(_paramName, _paramValue);
                Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
            }
        }
    
        public class BuildStrategy<TInterface> : BuilderStrategy
        {
            private readonly string _paramName;
            private readonly object _paramValue;
    
            public BuildStrategy(string paramName, object paramValue)
            {
                _paramName = paramName;
                _paramValue = paramValue;
            }
    
            public override void PreBuildUp(IBuilderContext context)
            {
                if (typeof(TInterface).IsAssignableFrom(context.OriginalBuildKey.Type))
                {
                    context.AddResolverOverrides(new ParameterOverride(_paramName, _paramValue));
                }
            }
        }
    

    You need the custom UnityContainerExtension, because you cannot access to the collection of BuilderStrategy from UnityContainer without reflection.

    And so you only need to add this extension to UnityContainer and try to resolve a type that you want:

        var container = new UnityContainer();
        container.AddExtension(new UnityExtension<IFoo>("id", "123"));
    
        var class1 = container.Resolve<MyClass>();
        var class2 = container.Resolve<MyClass2>();
    
        // show 123
        Console.WriteLine(class1.Id);  
    
        // show 123
        Console.WriteLine(class2.Id);