Pergunta

I'm using an architecture based on this implementation of the onion architecture. I have decided to challenge myself to change out NHibernates default logger (log4net) with NLog. I understand how to configure NLog, but I'm having trouble resolving my dependency for my logger in my LogerFactory class. Currently, my NHibernate project only knows my logging interface. How can I get my NHibernate project to resolve the dependency?

This is my program structure right now: Console App initializes ninject and sets up my modules, including my LoggingModule and my RepositoryModule. The very first time I need something from my repository, my SessionHelper class builds my session and configures NHibernate. This is where NHibernate calls my LoggerFactory (LoggerFactory implements NHibernates ILoggerFactory). NHibernate calls LoggerFor(Type type); type is passed in as NHibernate.Cfg.Configuration. From here, I need to get an instance of NLog through my ILoggingService, this is where I'm confused. How do I resolve this dependency here? My Console App knows about the resolution because that is where I built the kernel and loaded the modules. Do I just set up another kernel here? What is the best way to solve this?

Edit: Here is my current code:

Program.cs

namespace ZeroBase.ManualConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            IKernel kernel = CreateKernel();

            CoreService service = new CoreService(
                kernel.Get<ZeroBase.Domain.Interfaces.IUserRepository>(), 
                kernel.Get<ZeroBase.Domain.Interfaces.ICommentRepository>());

            //.........

        }

        static IKernel CreateKernel()
        {
            IKernel kernel = new StandardKernel();
            RegisterServices(kernel);
            return kernel;
        }

        static void RegisterServices(IKernel kernel)
        {
            // Bind Core Service
            kernel.Bind<ICoreService>().To<CoreService>();

            // Add data and infrastructure modules
            var modules = new List<INinjectModule>
            {
                new ConfigModule(),
                new LoggingModule(),
                new RepositoryModule()
            };

            kernel.Load(modules);
        }

    }
}

LoggingModule.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Modules;
using ZeroBase.Infrastructure.Interfaces;
using NLog.Config;
using NLog;
using ZeroBase.Infrastructure.Logging;

namespace ZeroBase.Infrastructure.DependencyResolution
{
    public class LoggingModule : NinjectModule
    {
        public override void Load()
        {
            ILoggingService logger = GetLoggingService();
            Bind<ILoggingService>().ToConstant(logger);
        }

        private ILoggingService GetLoggingService()
        {
            ConfigurationItemFactory.Default.LayoutRenderers
                .RegisterDefinition("utc_date", typeof(UtcDateRenderer));
            ConfigurationItemFactory.Default.LayoutRenderers
                .RegisterDefinition("web_variables", typeof(WebVariablesRenderer));
            ILoggingService logger = (ILoggingService)LogManager.GetLogger("NLogLogger", typeof(LoggingService));
            return logger;
        }
    }
}

RepositoryModule.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Ninject;
using Ninject.Modules;

using ZeroBase.Infrastructure.Interfaces;
using ZeroBase.Domain.Interfaces;
using ZeroBase.Infrastructure.Data;

namespace ZeroBase.Infrastructure.DependencyResolution
{
    public class RepositoryModule : NinjectModule
    {
        public override void Load()
        {
            SetupLogging();
            BindRepositories();
        }

        private void SetupLogging()
        {
            // Get logging service
            var loggingService = Kernel.Get<ILoggingService>();

        }

        private void BindRepositories()
        {
            // Get config service
            var configService = Kernel.Get<IConfigService>();

            // Bind repositories
            Bind<IUserRepository>().To<UserRepository>()
                .WithConstructorArgument("connectionString",    configService.ZeroBaseConnection);
            Bind<ICommentRepository>().To<CommentRepository>()
                .WithConstructorArgument("connectionString",    configService.ZeroBaseConnection);
        }
    }
}

RepositoryBase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZeroBase.Domain.Interfaces;

namespace ZeroBase.Infrastructure.Data
{
    public class RepositoryBase<T> : IRepositoryBase<T>
    {
        protected SessionHelper _nhibernate;
        protected string _connectionString;

        public RepositoryBase(string connectionString)
        {
            _connectionString = connectionString;
            _nhibernate = new SessionHelper(_connectionString);
        }

        //....
    }
}

SessionHelper.cs Builds the NHibernate session and configures. Notice that connectionString is being injected. I could easily inject the logging service here.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using ZeroBase.Infrastructure.Data;
using FluentNHibernate.Automapping;
using ZeroBase.Domain.Entities;
using ZeroBase.Infrastructure.Interfaces;

namespace ZeroBase.Infrastructure.Data
{
    public class SessionHelper
    {
        private ISessionFactory _sessionFactory;
        private string _connectionString;

        public SessionHelper(string connectionString)
        {
            _connectionString = connectionString;
        }

        private ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    InitializeSessionFactory();

                return _sessionFactory;
            }
        }

        private void InitializeSessionFactory()
        {
            _sessionFactory = Fluently.Configure()

                // Set up database connection
                .Database(MsSqlConfiguration.MsSql2005
                    .ConnectionString(x => x.Is(_connectionString))
                    //.ShowSql()
                )

                // Use class mappings
                .Mappings(m => m.FluentMappings
                    .AddFromAssemblyOf<UserMap>()
                    .AddFromAssemblyOf<ZeroBase.Infrastructure.Data.RACS3.UserMap>())

                .ExposeConfiguration(c => {
                        c.SetInterceptor(new AuditInterceptor());
                    }
                )

                .BuildSessionFactory();
        }

        public ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

LoggerFactory.cs Configured via app.config for NHibernate to use for its logging. This is where I'm having my dependency issue. This lives alongside NHibernate. I could easily reference NLog here and wire it up with NHibernate, but I do not want NHibernate to care what logging framework im using. This is why I would like to only deal with my interface and let Ninject inject my concrete implementation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using ZeroBase.Infrastructure.Interfaces;

namespace ZeroBase.Infrastructure.Data
{
    public class LoggerFactory : ILoggerFactory
    {
        public IInternalLogger LoggerFor(Type type)
        {
            //ILoggingService logService;

            // Get resolved LoggingService

            //return new NLogLogger(LogManager.GetLogger(type.FullName));
            //return new Logger(logService.GetLogger(type.FullName));
            return null;
        }

        public IInternalLogger LoggerFor(string keyName)
        {
            //ILoggingService logService;

            // Get resolved LoggingService

            //return new NLogLogger(LogManager.GetLogger(keyName));
            //return new Logger(logService.GetLogger(keyName));
            return null;
        }
    }

    public class Logger : IInternalLogger
    {
        private readonly ILoggingService logger;

        public Logger(ILoggingService _logger)
        {
            logger = _logger;
        }

        //....
    }
}
Foi útil?

Solução

Why can't you add a static Kernal property to your LoggerFactory class, and set that in your Program.Main, right after you've initialized the Kernal?

Then in your LoggerFor implementations, you just have to refer to your static kernal property to get the correctly bound implementation.

Outras dicas

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top