Autofac:如何使用动态值注入属性?

时间:2013-04-20 03:08:56

标签: c# .net autofac

通过Autofac,可以很容易地将CurrentDate属性的静态值注入给定程序集中的类的实例:

builder.RegisterApiControllers(asm).WithProperty("CurrentDate", new DateTime(2012, 1, 13));

然而,如何注入动态值,例如lamda () => { return DateTime.Now; }返回CurrentDate属性的值?

4 个答案:

答案 0 :(得分:1)

听起来你可以使用非常标准的属性注入,如下所示:

builder.RegisterApiControllers(asm)
    .OnActivating(e => { e.Instance.CurrentDate = DateTime.Now; });

请注意,您可能需要转换e.Instance,因为它可能是Object类型。

有关详细信息,请参阅Lifetime Events in the documentation

第二个想法,为什么不把初始化放在基类构造函数中?

public DateTime CurrentDate { get; private set; }
protected ApiController() { CurrentDate = DateTime.Now; }

当前日期并不是您需要DI容器提供的依赖项。

答案 1 :(得分:0)

注册另一个提供动态值的服务(例如IDateTimeService)[我认为它确实比你想要的DateTime更复杂。]这个新服务的默认生命周期为Instance per dependency但是你可以使用“Per Matching Lifetime Scope”。您的控制器已经根据Http请求创建。

现在只需在IDateTimeService(在构造函数中)中添加控制器的依赖项。在该控制器中的方法中,您现在可以获得所需的动态值。

private static readonly IDateTimeService datetimeService;

public MyController (IDateTimeService datetimeService)
{
   this.datetimeService = datetimeService;
}


public void SomeMethod()
{
     var date = datetimeService.GetDate();
     ...
}

答案 2 :(得分:0)

您需要编写自定义参数,如下所示:

public class DelegateParameter : Parameter
{
    private readonly string _name;
    private readonly Func<object> _getValue;

    public DelegateParameter(string name, Func<object> getValue)
    {
        if (name == null) throw new ArgumentNullException("name");
        if (getValue == null) throw new ArgumentNullException("getValue");
        _name = name;
        _getValue = getValue;
    }

    public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, out Func<object> valueProvider)
    {
        PropertyInfo propertyInfo = GetProperty(pi);
        if (propertyInfo == null || propertyInfo.Name != _name)
        {
            valueProvider = null;
            return false;
        }
        valueProvider = _getValue;
        return true;
    }

    private static PropertyInfo GetProperty(ParameterInfo pi)
    {
        var methodInfo = pi.Member as MethodInfo;
        if (methodInfo != null && methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_", StringComparison.Ordinal) && methodInfo.DeclaringType != null))
            return methodInfo.DeclaringType.GetProperty(methodInfo.Name.Substring(4));
        return null;
    }
}

然后使用它:

builder.RegisterApiControllers(asm).WithProperty(new DelegateParameter("CurrentDate", () => DateTime.Now));

答案 3 :(得分:-1)

如果您尝试注入lambda表达式,而不是lambda表达式的结果,那么您有很多不完美的选项。这里仅仅是少数;我相信还有更多。

Autofac

Google Project Hosting documents four ways of injecting properties上的Autofac wiki。其中三个似乎使用常量或默认值 - 您提到了其中一种方法。

最终似乎让开发人员对属性有了更多的控制权。它使用OnActivating事件,在此期间您有几个选项。你可以:

  • 设置属性并希望它坚持。
  • 如果属性缺少可访问的setter,则可以使用反射来设置它或其支持属性(默认情况下,对于名为PropertyName的属性,m_PropertyName,如果我没记错的话)。
  • 将实例包装在代理中,如下所示:请参阅下面的多面性

多态性

ClassA包含要修改的属性Prop1。创建一个扩展ClassB的新类ClassA。如果Prop1具有virtual修饰符,则可以覆盖它。否则,请使用new修饰符在ClassB中创建包含动态代码的类似属性。

如果是覆盖,则需要实例化ClassB代替ClassA。如果框架创建自己的ClassA实例,这将不起作用,但只要您创建自己的ClassB实例并将它们传递给框架,您就应该好了。

如果您正在使用新属性,除了实例化ClassB之外,您还必须确保无论何时访问新属性,对象都会转换为ClassB或后代类型。如果另一个框架设计为使用ClassA,则通常无效,因为无论您的演员如何,它都将始终在ClassA类型而不是ClassB上运行。

字节码操作

这是令人讨厌的东西,但它会完全符合您的要求。 C#通常编译为称为CIL的汇编/字节码语言。微软的变体是MSIL,但它与通用CIL非常相似。

我总是使用Mono.Cecil进行CLI / CLR(.NET,Mono)字节码操作。它看起来完美无瑕,一旦掌握了它就很好。但是,你必须知道两件事:

  1. 如何使用CIL
  2. 如何使用Mono.Cecil
  3. 第一个并不是那么糟糕。只要您有足够的CLI使用经验,就可以获得一些包含详细表格的维基百科页面。如果您认为CLI仅代表“命令行界面”,那么您可能会遇到困难。

    另一方面,Mono.Cecil在大约一年前(2012年)缺乏任何形式的适当文件。学习曲线不可能陡峭。我有一个悲惨的几天试图搞清楚。但是,它的工作原理令人惊叹。