Autofac PropertiesAutowired - 是否可以忽略一个或多个属性?

标签 autofac

尽管建议通过构造函数传递依赖项,但我发现使用无参数构造函数然后 Autowiring 所有属性的开发成本显着减少,并且使应用程序更易于开发和维护。然而有时(例如在 View 模型上)我有一个向容器注册的属性,但我不想在构造时填充该属性(例如绑定(bind)到容器的所选项目)。

有没有办法告诉容器在 Autowiring 其余属性时忽略某些属性?

目前,我只是重置在激活事件中用属性标记的属性:

public static IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> 
    PropertiesAutowiredExtended<TLimit, TRegistrationStyle>(
    this IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> builder)
{
    builder.ActivatorData.ConfigurationActions.Add(
        (type, innerBuilder) =>
        {
            var parameter = Expression.Parameter(typeof(object));
            var cast = Expression.Convert(parameter, type);
            var assignments = type.GetProperties()
                .Where(candidate => candidate.HasAttribute<NotAutowiredAttribute>())
                .Select(property => new { Property = property, Expression = Expression.Property(cast, property) })
                .Select(data => Expression.Assign(data.Expression, Expression.Default(data.Property.PropertyType)))
                .Cast<Expression>()
                .ToArray();

            if (assignments.Any())
            {
                var @action = Expression
                    .Lambda<Action<object>>(Expression.Block(assignments), parameter)
                    .Compile();

                innerBuilder.OnActivated(e =>
                {
                    e.Context.InjectUnsetProperties(e.Instance);
                    @action(e.Instance);
                });
            }
            else
            {
                innerBuilder.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));
            }
        });

    return builder;
}

有更好的方法吗?

最佳答案

不确定这是否更好,但您可以从另一侧出发,通过 WithProperty 语法仅注册所需的属性。优点是 Autofac 不会解决不必要的服务。这是一个有效的示例:

public class MyClass
{
    public MyDependency MyDependency { get; set; }
    public MyDependency MyExcludeDependency { get; set; }
}
public class MyDependency {}

public class Program
{
    public static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyDependency>();
        builder.RegisterType<MyClass>().WithPropertiesAutowiredExcept("MyExcludeDependency");

        using (var container = builder.Build())
        {
            var myClass = container.Resolve<MyClass>();

            Console.WriteLine(myClass.MyDependency == null);
            Console.WriteLine(myClass.MyExcludeDependency == null);
        }
    }
}

public static class PropertiesAutowiredExtensions
{
    // Extension that registers only needed properties
    // Filters by property name for simplicity
    public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
        WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
        this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
        params string[] propertiesNames)
        where TReflectionActivatorData : ReflectionActivatorData
    {
        var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;

        foreach (var property in type
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
        {
            // There's no additional checks like in PropertiesAutowired for simplicity
            // You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties

            var localProperty = property;
            registrationBuilder.WithProperty(
                new ResolvedParameter(
                    (pi, c) =>
                        {
                            PropertyInfo prop;
                            return pi.TryGetDeclaringProperty(out prop) &&
                                   prop.Name == localProperty.Name;
                        },
                    (pi, c) => c.Resolve(localProperty.PropertyType)));
        }

        return registrationBuilder;
    }

    // From Autofac.Util.ReflectionExtensions
    public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
    {
        var mi = pi.Member as MethodInfo;
        if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
            && mi.DeclaringType != null)
        {
            prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
            return true;
        }

        prop = null;
        return false;
    }
}

关于Autofac PropertiesAutowired - 是否可以忽略一个或多个属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21606629/

相关文章:

c# - 如何使用 AutoFac 解析正确的记录器类型?

c# - 没有注册类型 'IServiceProviderFactory[Autofac.ContainerBuilder]' 的服务

c# - Autofac.WebApi2 全局操作过滤器注入(inject)失败

c# - 区分应用程序处理程序中的 Web API 请求和 MVC 请求

c# - Autofac。如何使用自定义方法(属性)来解析一些接口(interface)?

c# - 使用 AutoFac 的通用复杂类型注册通用类型

dependency-injection - Autofac 未解决模型绑定(bind)器依赖项

multithreading - 如何使用 Autofac 从 MVC Controller 创建背景任务?

asp.net-mvc - AOP vs MVC FilterAttributes vs Interceptors

asp.net-mvc - ServiceStack MemoryCacheClient 不缓存