Использование Ninject для заполнения зависимости Log4Net
Я использую Ninject в качестве контейнера DI в своем приложении. Чтобы свободно подключиться к моей библиотеке регистрации, я использую такой интерфейс:
public interface ILogger
{
void Debug(string message);
void Debug(string message, Exception exception);
void Debug(Exception exception);
void Info(string message);
...you get the idea
И моя реализация выглядит так:
public class Log4NetLogger : ILogger
{
private ILog _log;
public Log4NetLogger(ILog log)
{
_log = log;
}
public void Debug(string message)
{
_log.Debug(message);
}
... etc etc
Примерный класс с зависимостью журнала
public partial class HomeController
{
private ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
При создании экземпляра Log4Net вы должны указать ему имя класса, для которого он будет регистрироваться. Это является проблемой с Ninject.
Цель состоит в том, что при создании экземпляра HomeController, Ninject должен создать экземпляр ILog с именем "HomeController"
Вот что у меня для config
public class LoggingModule : NinjectModule
{
public override void Load()
{
Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
.InSingletonScope();
Bind<ILogger>().To<Log4NetLogger>()
.InSingletonScope();
}
private string GetParentTypeName(IContext context)
{
return context.Request.ParentContext.Request.ParentContext.Request.Service.FullName;
}
}
Однако "Имя", которое передается ILog, не то, что я ожидаю. Я не могу понять ни рифмы, ни причины, иногда это правильно, но в большинстве случаев это не так. Имена, которые я вижу, это имена ДРУГИХ классов, которые также имеют зависимости от ILogger.
Ответы
Ответ 1
Расширение Ninject.Extension.Logging уже предоставляет все, что вы реализуете самостоятельно. Включая поддержку log4net, NLog и NLog2.
https://github.com/ninject/ninject.extensions.logging
Также вы хотите использовать следующие типы регистратора:
context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType
В противном случае вы получите регистратор для типа службы вместо типа реализации.
Ответ 2
Я лично не заинтересован в абстрагировании моего регистратора, поэтому мои модули реализации ссылаются на log4net.dll
напрямую, а мои конструкторы запрашивают ILog
по желанию.
Для этого однострочная регистрация с использованием Ninject v3 выглядит так в конце моего static void RegisterServices( IKernel kernel )
:
kernel.Bind<ILog>().ToMethod( context=>
LogManager.GetLogger( context.Request.Target.Member.ReflectedType ) );
kernel.Get<LogCanary>();
}
class LogCanary
{
public LogCanary(ILog log)
{
log.Debug( "Debug Logging Canary message" );
log.Info( "Logging Canary message" );
}
}
Для облегчения диагностики проблем с протоколированием я вначале прикладываю следующее сообщение:
public static class NinjectWebCommon
{
public static void Start()
{
LogManager.GetLogger( typeof( NinjectWebCommon ) ).Info( "Start" );
Что дает начало приложению:
<datetime> INFO MeApp.App_Start.NinjectWebCommon - Start
<datetime> DEBUG MeApp.App_Start.NinjectWebCommon+LogCanary - Debug Logging Canary message
<datetime> INFO MeApp.App_Start.NinjectWebCommon+LogCanary - Logging Canary message
Ответ 3
Объем ILog
и ILogger
должен быть временным, иначе он просто повторно использует первый созданный журнал. Спасибо @Meryln Morgan-Graham за то, что помогли мне найти это.
Ответ 4
Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
.InSingletonScope();
В настоящее время вы привязываетесь к области Singleton, поэтому создается только один регистратор, который будет использовать имя созданного первого. Вместо этого используйте InTransientScope()
Ответ 5
Возможно, мой ответ задерживается, но я использую этот формат:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILog>()
.ToMethod(c => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
.InSingletonScope();
}
Ответ 6
Для всех вас, которые все еще ищут правильный ответ, правильная реализация:
public class LoggingModule : NinjectModule
{
public override void Load()
{
Bind<ILog>().ToMethod(x => LogManager.GetLogger(x.Request.Target.Member.DeclaringType));
Bind<ILogger>().To<Log4NetLogger>()
.InSingletonScope();
}
}
Акцент на:
x.Request.Target.Member.DeclaringType
Ответ 7
Мне нравится идея переноса Log4Net в мои собственные интерфейсы. Я не хочу быть зависимым от реализации Ninjects, потому что для меня это просто означает, что я беру зависимость от Ninject во всем моем приложении, и я думал, что это была полная противоположность тому, для чего предназначена инъекция зависимостей. Отделить от сторонних служб. Поэтому я взял исходный код плакатов, но я изменил следующий код, чтобы он работал.
private string GetParentTypeName(IContext context)
{
var res = context.Request.ParentRequest.ParentRequest.Service.FullName;
return res.ToString();
}
Мне нужно вызвать ParentRequest.ParentRequest, чтобы при печати макета% logger он напечатал класс, который вызывает метод журнала Log4Net, вместо класса Log4Net метода, который вызвал метод журнала.