Что является недостатком ручной регистрации экземпляр, такой как log4net регистратор, чтобы выйти из кратера в Autofac?


Autofac имеетмодуль интеграции log4net , называемыйLoggingModule .

Однако, я зарегистрироваться регистратор в выйти из кратера вручную, без использования LoggingModule, и, кажется, работает нормально.

ILog log = LogManager.GetLogger("Logger");
builder.RegisterInstance(log).As<ILog>().SingleInstance();

Мой вопрос - что является недостатком/побочный эффект использования вышеуказанного подхода вместо того, чтобы использовать LoggingModule.

Паутина.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="mylogfile.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingFileAppender" />
    </root>
  </log4net>
</configuration>

Глобальный.асакс.cs

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace DemoLog4NetAuftofac
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            var builder = new ContainerBuilder();

            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            ILog log = LogManager.GetLogger("Logger");
            builder.RegisterInstance(log).As<ILog>().SingleInstance();

            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

HomeController

namespace DemoLog4NetAuftofac.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(ILog log)
        {
            log.Debug("Debug application");
            log.Error("Error application");
            log.Info("Info application");
        }
    }
}

Версия

  <package id="Autofac" version="3.4.0" targetFramework="net45" />
  <package id="Autofac.Mvc5" version="3.3.4" targetFramework="net45" />
  <package id="log4net" version="2.0.3" targetFramework="net45" />
2 2

2 ответа:

LoggingModule, предоставляемыйAutofac , является усовершенствованным образцом пользовательского модуля.

Единственное различие между этим модулем и пользовательской регистрацией заключается в том, что модуль будет использовать разные экземпляры ILog для каждого типа, в котором он вводится, тогда как в вашем коде вы будете использовать только один экземпляр ILog.

Например:

public class Foo
{
    public Foo(ILog log)
    { 
        Console.WriteLine(log.Logger.Name);
    }
}
public class Bar
{
    public Bar(ILog log)
    { 
        Console.WriteLine(log.Logger.Name);
    }
}

С вашей таможенной регистрацией log, введенной в Foo и Bar, будет то же самое, и они будут результатом LogManager.GetLogger("Logger"). Если ты используйте LoggingModule log будет результатом LogManager.GetLogger(typeof(Foo)) для Foo и LogManager.GetLogger(typeof(Bar)) для Bar.

Наличие другого экземпляра ILog поможет вам фильтровать журнал для определенного типа и тому подобное.

Ваша регистрация не имеет проблем, но использование LoggingModule позволит вам фильтровать или указывать уровень журнала для некоторого класса или пространства имен.

Кстати, я рекомендую вам прочитать исходный код LoggingModule, это не очень сложно, и это поможет вам лучше понять, как модуль ипараметр работают сAutofac .

Я бы даже пошел дальше и сказал, что вводить ILog непосредственно в ваш код неправильно. Даже если ILog является абстракцией, вы все равно нарушите принцип инверсии зависимостей , потому что:

В прямом применении инверсии зависимостей, абстракты являются принадлежит верхним / политическим слоям

В то время как в вашем случае абстракция ILog принадлежит нижнему уровню (внешней библиотеке журналов).

Это плохо, потому что такая абстракция в общее определяется так, как это нравится фреймворку, а не вашему коду. Поэтому он загрязняет ваш код и, кроме того, заставляет ваш код все еще находиться в жесткой зависимости от внешней библиотеки. Это затрудняет последующую замену библиотеки журналов на другую.

Но в случае log4net это становится еще хуже, потому что интерфейс ILog является большим нарушением принципа сегрегации интерфейса, потому что он содержит 40 членов. Это делает API намного более сложный, чем требуется, и делает его гораздо труднее имитировать реализацию.

Вместо этого было бы гораздо лучше создать абстракцию для ведения журнала, специфичную для приложения (предпочтительно с одним членом, как показано в этом примере ). Когда вы определили абстракцию ведения журнала с одним членом, будет тривиально создать адаптер для log4net, Enterprise Library Logging Application Block, ELMAH или любой другой библиотеки ведения журнала, которую вы можете придумать.

И не забудьте спросить себя:: я записываю слишком много ?