How to inject dependency name as a constructor parameter

后端 未结 2 983
故里飘歌
故里飘歌 2021-01-05 22:20

Using Autofac, I can register a class to resolve against an interface using property injection, using the following code:

builder.RegisterType

        
相关标签:
2条回答
  • 2021-01-05 22:57

    You only use logName to effectively resolve by name an ILog, so why not just inject an ILog?

    public class Log4NetAdapter : ILogger
    {
        private readonly ILog _logger;
    
        public Log4NetAdapter(ILog logger)
        {
            _logger = logger;
        }
    
        ...
    }
    

    OK, so now I've just moved the problem a bit, but I've also made this less coupled to other classes, namely the LogManager.

    So if I was using unity, I would then do this to ensure I get the right logger:

    var childContainer = container.CreateChildContainer();
    childContainer.RegisterInstance<ILog>(LogManager.GetLogger(logName));
    var adaptor = childContainer.Resolve<Log4NetAdapter>();
    

    The child container prevents any other code getting access to that ILog. You can do this as high up as you like, I don't know any more about your code.

    0 讨论(0)
  • 2021-01-05 23:00

    Update: Building on the LogInjectionModule sample and how Autofac does property injection, I have extended the module to do both constructor and property injection.

    Note: I've fixed the type passed to LogManager in OnComponentPreparing to use the declaring type. This makes e.g. Resolve<Func<Service>> use the correct log type.

        using System.Linq;
        using log4net;
    
        public class LogInjectionModule : Module
        {
            protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration)
            {
                registration.Preparing += OnComponentPreparing;
                registration.Activating += OnComponentActivating;
            }
    
            private static void OnComponentActivating(object sender, ActivatingEventArgs<object> e)
            {
                InjectLogProperties(e.Context, e.Instance, false);
            }
    
            private static void OnComponentPreparing(object sender, PreparingEventArgs e)
            {
                e.Parameters = e.Parameters.Union(new[]
                    {
                        new ResolvedParameter(
                           (p, i) => p.ParameterType == typeof(ILog),
                           (p, i) => LogManager.GetLogger(p.Member.DeclaringType))
                    });
            }
    
            private static void InjectLogProperties(IComponentContext context, object instance, bool overrideSetValues)
            {
                if (context == null) throw new ArgumentNullException("context");
                if (instance == null) throw new ArgumentNullException("instance");
    
                var instanceType = instance.GetType();
                var properties = instanceType
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(pi => pi.CanWrite && pi.PropertyType == typeof(ILog));
    
                foreach (var property in properties)
                {
                    if (property.GetIndexParameters().Length != 0)
                        continue;
    
                    var accessors = property.GetAccessors(false);
                    if (accessors.Length == 1 && accessors[0].ReturnType != typeof(void))
                        continue;
    
                    if (!overrideSetValues &&
                        accessors.Length == 2 &&
                        (property.GetValue(instance, null) != null))
                        continue;
    
                    ILog propertyValue = LogManager.GetLogger(instanceType);
                    property.SetValue(instance, propertyValue, null);
                }
            }
        }
    

    On how to use the module, here's a sample:

    public class Service
    {
        public Service(ILog log) { ... }
    }
    
    var cb = new ContainerBuilder();
    cb.RegisterModule<LogInjectionModule>();
    cb.RegisterType<Service>();
    var c = cb.Build();
    
    var service = c.Resolve<Service>();
    
    0 讨论(0)
提交回复
热议问题