zcz527 / autofac

Automatically exported from code.google.com/p/autofac
Other
0 stars 0 forks source link

PropertiesAutowired ignores Resolve parameters when it is testing what props can be wired #289

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Windsor is able to autowire properties using arguments passed to resolve.

This doesn't appear to work in autofac. 2.4.3.700

public class A
{
  public string MyProp { get; set;}
}
...
builder.RegisterType<A>().PropertiesAutowired();
...
container.Resolve(typeof(A), new NamedPropertyParameter("MyProp", "hello"));

===> I would expect MyProp to be set to "hello".

Original issue reported on code.google.com by tom8...@gmail.com on 3 Feb 2011 at 2:30

GoogleCodeExporter commented 8 years ago
Thanks for raising this. Autofac is a lot less supportive of Property Injection 
in Windsor, but the API here is misleading. I'll look into what can be done 
about it, although the parameter architecture of Autofac might make this 
inefficient to do by default.

Original comment by nicholas...@gmail.com on 9 Mar 2011 at 9:35

GoogleCodeExporter commented 8 years ago
For what it is worth, here is how I added an extension to achieve this...

using System;
using Autofac.Builder;
using Autofac.Core;
using System.Reflection;
using Autofac;
using System.Collections.Generic;

// Note: Regular autofac autowiring propertyinjector sets all properties, even 
if they are already set.
// Hence components should NOT expose settable properties that are ALSO 
initialised by ctor parameter.

namespace Blah
{
  public static class AutofacExtensions
  {
    /// <summary>
    /// Special autowiring mode that also scans Resolve parameters while wiring properties
    /// </summary>
    public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> PropertiesAutowiredWithParameters<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> rb)
    {
      AutowiringPropertyInjectorWithParameters injector = new AutowiringPropertyInjectorWithParameters();
      rb.RegistrationData.ActivatingHandlers.Add(delegate(object s, ActivatingEventArgs<object> e)
      {
        injector.InjectProperties(e.Context, e.Instance, e.Parameters);
      });
      return rb;
    }
    /// <summary>
    /// Special autowiring mode that also scans Resolve parameters while wiring properties
    /// </summary>
    public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> PropertiesAutowiredWithParameters<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> rb, bool allowCircularDependencies)
    {
      if (allowCircularDependencies)
      {
        AutowiringPropertyInjectorWithParameters injector = new AutowiringPropertyInjectorWithParameters();
        rb.RegistrationData.ActivatedHandlers.Add(delegate(object s, ActivatedEventArgs<object> e)
        {
          injector.InjectProperties(e.Context, e.Instance, e.Parameters);
        });
        return rb;
      }
      return rb.PropertiesAutowired();
    }
  }

  internal class AutowiringPropertyInjectorWithParameters
  {
    public void InjectProperties(IComponentContext context, object instance, IEnumerable<Parameter> parameters)
    {
      if (context == null)
      {
        throw new ArgumentNullException("context");
      }
      if (instance == null)
      {
        throw new ArgumentNullException("instance");
      }
      foreach (PropertyInfo info in instance.GetType().GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance))
      {
        Type propertyType = info.PropertyType;
        if (!propertyType.IsValueType && info.GetIndexParameters().Length == 0)
        {
          MethodInfo[] accessors = info.GetAccessors(false);
          if (accessors.Length != 1 || accessors[0].ReturnType == typeof(void))
          {
            foreach (Parameter p in parameters)
            {
              Func<object> func;
              if (p.CanSupplyValue(info.GetSetMethod().GetParameters()[0], context, out func))
              {
                info.SetValue(instance, func(), null);
                goto next_prop;
              }
            }
            if (context.IsRegistered(propertyType))
            {

              object obj2 = context.Resolve(propertyType);
              info.SetValue(instance, obj2, null);
            }
          next_prop: ;
          }
        }
      }
    }
  }
}

Original comment by tom8...@gmail.com on 9 Mar 2011 at 1:59

GoogleCodeExporter commented 8 years ago
I would also like to note that it's hard to opt-in the default property 
autowiring behavior. You have to implement the InjectProperties method as in 
the comment above from scratch every time you need to alter some aspects, for 
example to inject only properties marked with special attribute, or to consume 
some metadata from property attributes etc.

Original comment by mrdont@mail.ru on 11 Nov 2011 at 10:03

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 21 Sep 2012 at 4:30

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 2 Jan 2013 at 11:15

GoogleCodeExporter commented 8 years ago
Moved issue to GitHub: https://github.com/autofac/Autofac/issues/289

Subsequent issue management will be held there; closing the issue on Google 
Code as "WontFix" because we will handle issue resolution on GitHub.

Original comment by travis.illig on 11 Feb 2014 at 12:06