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
source to share
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).
source to share