Ninject injection into constructor, field or attribute method

I am wondering if the following is possible, and if so, how to do it. I will try to explain this with the code below.

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.
}

      

I want to enter ILogScopeInterceptorFactory

in LogScopeAttribute

using Ninject, so I do not need to call the kernel inside the method CreateInterceptor

and insert objects ConstructorArgument

I would do it like this ...

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);
    }
}

      

This is the interface ILogScopeInterceptorFactory

that I link to Ninject.extensions.Factory

for example:

Bind<ILogScopeInterceptorFactory>().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();
}

      

Now what I want to do is still use LogScopeAttribute

like this [LogScope("Start", "End")]

No need to manually insert the factory, just inject it, how can I do this?

EDIT2:

I am using log4net to login, I will just write here what it does LogScopeAttribute

, AND what the result looks like.

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

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

      

For ninject to intercept all methods, they must be public

and virtual

. I find it quite convenient for logging, it's easy to step back from everything that goes into the method AND if I need a header and footer, or print the runtime for the whole method. It can also be nested ...

@FELIX

The problem is not that I can't get the kernel ... If I wanted to create a factory by calling the kernel, I could do it like this.

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

      

If I were to manually insert the factory, I would have to do this for each attribute

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

      

And it'll just be uggly

+3


source to share


1 answer


Since you cannot make something executable like in an attribute ... you have to cheat ...

The container is global, so I always create it using the singleton template ...



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>();
}

      

Usually, of course, the use Container.Current.Get

is anti-pattern. However, in some situations this is necessary (for example, attributes). In a perfect world, the attribute would be very subtle - ILogScopeInterceptorFactory

do all the work (and be tested by the class).

0


source







All Articles