Search code examples
c#.netautofac

Passing parameters to dependencies through a next level service


I understand how to resolve a named parameter if I resolve exactly that service which has that parameter. But the thing is that in my case I have such service as a dependecy. Here is the example:

class Program
{
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<Dependency>();
        builder.RegisterType<Something>();
        var container = builder.Build();
        container.Resolve<Dependency>(new NamedParameter("prm", "test"));
        container.Resolve<Something>(new NamedParameter("prm", "test")); //Fails
    }
}

class Dependency
{
    public Dependency(string prm) { }
}

class Something
{
    public Something(Dependency dep) { }
}

It fails on the second Resolve call but I need something like this. Could you please advise something to solve it? Maybe I shoud mark the parameter to be something like this:

container.Resolve<Something>(new NamedParameter<Dependency>("prm", "test"));

Solution

  • This is how I fixed my particular problem. It supports both dynamic (run-time) and static (compile-time) values:

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Dependency2>();
            builder.RegisterGeneric(typeof(SomethingFactory<>));
            builder.RegisterType<Something>().WithAttributeFiltering();
            var container = builder.Build();
    
            Console.WriteLine(container.Resolve<Something>()
                .GetPrm());
            Console.WriteLine(container.Resolve<SomethingFactory<Something>>()
                .GetService(new Dependency1("My test value from the factory")).GetPrm());
            Console.WriteLine("But the registration is " + container.IsRegistered<Dependency1>());
        }
    }
    
    class Dependency1
    {
        private readonly string _prm;
        public Dependency1(string prm) => _prm = prm;
        public string GetPrm() => _prm;
    }
    
    class Dependency2
    {
        private readonly Dependency1 _dep;
        public Dependency2(Dependency1 dep) => _dep = dep;
        public string GetPrm() => _dep.GetPrm();
    }
    
    class Something
    {
        private readonly Dependency2 _dep;
        public Something([Prm("My test value from the attribute")]Dependency2 dep) => _dep = dep;
        public string GetPrm() => _dep.GetPrm();
    }
    
    class Prm : ParameterFilterAttribute
    {
        private readonly string _prm;
    
        public Prm(string prm) => _prm = prm;
    
        public override bool CanResolveParameter(ParameterInfo parameter, IComponentContext context)
            => !context.IsRegistered<Dependency1>();
    
        public override object ResolveParameter(ParameterInfo parameter, IComponentContext context)
        {
            if (parameter == null)
            {
                throw new ArgumentNullException(nameof(parameter));
            }
    
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
            var container = context.Resolve<ILifetimeScope>();
            using var scope = container.BeginLifetimeScope(builder
                => builder.RegisterInstance(new Dependency1(_prm)));
            return scope.Resolve(parameter.ParameterType);
        }
    }
    
    class SomethingFactory<T>
    {
        private readonly ILifetimeScope _container;
    
        public SomethingFactory(ILifetimeScope container)
        {
            _container = container;
        }
    
        public T GetService(Dependency1 dep)
        {
            if (dep == null)
            {
                throw new ArgumentNullException(nameof(dep));
            }
    
            using var scope = _container.BeginLifetimeScope(builder => builder.RegisterInstance(dep));
            return scope.Resolve<T>();
        }
    }
    
    My test value from the attribute
    My test value from the factory
    But the registration is False