Uso de Ninject para rellenar la dependencia de Log4Net


Uso Ninject como contenedor DI en mi aplicación. Con el fin de acoplar libremente a mi biblioteca de registro, utilizo una interfaz como esta:

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

Y mi implementación se ve así

public class Log4NetLogger : ILogger
    {
        private ILog _log;

        public Log4NetLogger(ILog log)
        {
            _log = log;
        }

        public void Debug(string message)
        {
            _log.Debug(message);
        }
        ... etc etc

Una clase de ejemplo con una dependencia de registro

public partial class HomeController
    {
        private ILogger _logger;

        public HomeController(ILogger logger)
        {
            _logger = logger;
        }

Al instanciar una instancia de Log4Net, debe darle el nombre de la clase para la que se registrará. Esto está demostrando ser un desafío con Ninject.

El objetivo es que al instanciar HomeController, Ninject debería instanciar ILog con un "nombre"de" HomeController "

Esto es lo que tengo para 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;
        }
    }

Sin embargo, el "Nombre" que se está pasando a ILog no es lo que estoy esperando. No puedo entender ninguna rima o razón tampoco, a veces es correcto, la mayoría de las veces no lo es. Los Nombres que estoy viendo son nombres de OTRAS clases que también tienen dependencias en el ILogger.

Author: Brook, 2011-07-21

7 answers

El Ninject.Ampliación.La extensión de registro ya proporciona todo lo que está implementando usted mismo. Incluye soporte para log4net, NLog y NLog2.

Https://github.com/ninject/ninject.extensions.logging


También desea utilizar lo siguiente como tipo de registrador:

context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType

De lo contrario obtendrá el registrador para el tipo de servicio en lugar del tipo de implementación.

 18
Author: Remo Gloor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-21 19:56:27

Personalmente no tengo ningún interés en abstraer mi registrador, por lo que mis módulos de implementación hacen referencia a log4net.dll directamente y mis constructores solicitan un ILog como deseen.

Para lograr esto, un registro de una línea usando Ninject v3 se ve así al final de mi 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" );
        }
    }

Para facilitar el diagnóstico de problemas de registro, pego lo siguiente al principio para obtener un mensaje no impulsado por DI también:

public static class NinjectWebCommon
{
    public static void Start()
    {
        LogManager.GetLogger( typeof( NinjectWebCommon ) ).Info( "Start" );

Que produce lo siguiente al iniciar la aplicación:

<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
 26
Author: Ruben Bartelink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-30 16:16:29

El Ámbito de ILog y ILogger debe ser Transitorio, de lo contrario solo reutilizará el primer registrador que cree. Gracias a @ Meryln Morgan-Graham por ayudarme a encontrar eso.

 9
Author: Brook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-21 19:23:27
Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
            .InSingletonScope();

Actualmente está enlazando en el ámbito Singleton, por lo que solo se crea un registrador que utilizará el nombre del primero creado. En su lugar use InTransientScope()

 7
Author: BrokenGlass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-21 19:24:11

Para todos los que todavía están buscando la respuesta correcta, la implementación correcta es :

public class LoggingModule : NinjectModule
{
    public override void Load()
    {
        Bind<ILog>().ToMethod(x => LogManager.GetLogger(x.Request.Target.Member.DeclaringType));

        Bind<ILogger>().To<Log4NetLogger>()
            .InSingletonScope();
    }
}

Énfasis en:

x.Request.Target.Member.DeclaringType
 4
Author: regisbsb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-15 11:28:00

Tal vez mi respuesta es tarde, pero estoy usando este formato:

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ILog>()
            .ToMethod(c => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
            .InSingletonScope();
    }
 3
Author: Leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-06 13:51:15

Me gusta la idea de envolver Log4Net en mis propias interfaces. No quiero depender de la implementación de Ninjects, porque para mí eso solo significa que tomo una dependencia de Ninject a lo largo de mi aplicación y pensé que era exactamente lo contrario de lo que es la inyección de dependencia. Desacoplar de servicios de terceros. Así que tomé el código original de los carteles, pero cambié el siguiente código para que funcionara.

    private string GetParentTypeName(IContext context)
    {
        var res = context.Request.ParentRequest.ParentRequest.Service.FullName;
        return res.ToString();
    }

Tengo que llamar a ParentRequest.ParentRequest para que cuando imprima el layout % logger imprimirá la clase que llama al método Log4Net en lugar de la clase Log4Net del método que llamó al método Log.

 0
Author: mac10688,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-13 16:40:56