【问题标题】:Ninject inject into an attributes constructor, field or methodNinject 注入到属性构造函数、字段或方法中
【发布时间】:2013-01-12 19:37:45
【问题描述】:

我想知道以下是否可行,如果可以,该怎么做。 我会尝试用下面的代码来解释它。

public class RandomClass
{
    ...
    //class is filled with stuff of none importance for this demonstration
    ...

    [LogScope("Start", "End")] //The important LogScope attribute!
    public virtual void MyMethod()
    {
        ...
        //Doing something here but not the point now...
        ...
    }

    ...
}

public LogScopeAttribute : InterceptAttribute
{
    private readonly string _header;
    private readonly string _footer;

    public LogScopeAttribute(string header, string footer)
    {
        _header = header;
        _footer = footer;
        // This is just one of many constructors....
    }

    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return request.Context.Kernel.Get<LogScopeInterceptor>(
            new ConstructorArgument("header", _header),
            new ConstructorArgument("footer", _footer));
        // In the real version of this method there is more logic here for creating
        // the right version of the interceptor, in regards to what constrcutor the
        // LogScopeAttribute was called with.
    }
}

public class LogScopeInterceptor : SimpleInterceptor
{
    // No need to explain stuff here, (not of importance to the question)
    // but what the interceptor does for me is write to log
    // a header and footer and indent everything inside the logscope.
}

我想要的是用 Ninject 将 ILogScopeInterceptorFactory 注入到 LogScopeAttribute 中,这样我就不必在 CreateInterceptor 方法中调用内核,然后插入 ConstructorArgument 对象 我想这样做......

public LogScopeAttribute : InterceptAttribute
{
    private readonly string _header;
    private readonly string _footer;
    private readonly ILogScopeInterceptorFactory _logScopeInterceptorFactory;

    public LogScopeAttribute(ILogScopeInterceptorFactory logScopeInterceptorFactory ,string header, string footer)
    {
        _header = header;
        _footer = footer;
        _logScopeInterceptorFactory = logScopeInterceptorFactory;
    }

    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return _logScopeInterceptorFactory.Create(_header, _footer);
    }
}

这是我与Ninject.extensions.Factory 绑定的ILogScopeInterceptorFactory 接口 像这样:

Bind&lt;ILogScopeInterceptorFactory&gt;().ToFactory();

public interface ILogScopeInterceptorFactory
{
    LogScopeInterceptor Create(char separatorChar, string header, string footer);
    LogScopeInterceptor Create(char separatorChar, string header);
    LogScopeInterceptor Create(string header, string footer);
    LogScopeInterceptor Create(string header);
    LogScopeInterceptor Create(char separatorChar);
    LogScopeInterceptor Create();
}

现在我想做的仍然是像这样使用LogScopeAttribute [LogScope("Start", "End")] 不用手动插入工厂,直接注入,怎么办?

EDIT2:

我正在使用 log4net 进行登录,我将在这里写下 LogScopeAttribute 的作用, 以及输出的样子。

[LogScope("The Start", "The End")]
public virtual void MyMethod()
{
    logger.Info("Hello World!");
}

OUTPUT:
logger: The Start
logger:     Hello World!
logger: The End

为了让ninject拦截所有方法,它们需要是publicvirtual。 我发现这对于记录非常方便,可以轻松缩进方法中记录的所有内容 如果我想要页眉和页脚,或者打印该方法的执行时间,它就在那里。 这也可以嵌套...

@FELIX

问题不在于我无法获取内核... 如果我想通过调用内核来创建工厂,我可以这样做。

public override IInterceptor CreateInterceptor(IProxyRequest request)
{
    var factory = request.Context.Kernel.Get<ILogScopeInterceptorFactory>();
    return factory.Create(_header, _footer);
}

如果我手动插入工厂,我必须为每个属性都这样做

[LogScope(_logScopeInterceptorFactory, "header", "footer")]

那就太丑了

【问题讨论】:

    标签: c# attributes inversion-of-control ninject interceptor


    【解决方案1】:

    因为你不能在属性中做任何运行时......你将不得不作弊......

    容器是全局的,所以我总是使用单例模式创建它...

    public static class Container
    {
        private static IKernel _container;
    
        static Container()
        {
            _container = ...; //Create the kernel and define container
        }
    
        public static IKernel Current { get { return _container; } }
    }
    
    public LogScopeAttribute(string header, string footer)
    {
        _header = header;
        _footer = footer;
        _logScopeInterceptorFactory = Container.Current.Get<ILogScopeInterceptorFactory>();
    }
    

    当然,通常使用Container.Current.Get 是一种反模式。但是在某些情况下它是必需的(例如属性)。在理想情况下,该属性会非常小——ILogScopeInterceptorFactory 将完成所有工作(并且将是被测试的类)。

    【讨论】:

    • 您无权访问构造函数中的内核,并且无法注入 IResolutionRoot,就像我正在努力注入 ILogScopeInterceptorFactory 一样。但这可以在 CreateInterceptor 方法中完成,因为您可以通过 IProxyRequest 对象进入内核,但这会破坏这个问题的全部目的。
    • 对不起...看起来当我在研究这个问题时内核曾经是静态的或其他东西...让我更新我的答案
    • 我看不出这与做我已经在做的事情有什么不同,问题不在于获取内核,我已经拥有它......答案是否定的可能并解释为什么 imo。
    • 当然,没有问题...我只是将问题视为“无需手动插入工厂,只需注入它,我该怎么做?”。这是可能的 - 我举了一个例子......所以你不能真的说它不可能。当然可能会有更好的答案!
    • 没问题 :) 我编辑了我的问题并为您提供了答案,以便更好地在代码中演示。
    猜你喜欢
    • 2012-02-27
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多