Использование Autofac для внедрения log4net в контроллер

Пытаюсь использовать Autofac для внедрения класса log4net в мой контроллер, но получаю следующее исключение:

Ни один из конструкторов, обнаруженных с «общедоступными флагами привязки» для типа «MvcApplication6.Controllers.HomeController», не может быть вызван с доступными службами и параметрами: Невозможно разрешить параметр «log4net.ILog logger» конструктора «Void .ctor (log4net.ILog) '.

Я создал модуль для внедрения класса Log, используя правильный тип:

public class LogInjectionModule : Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration)
    {
         registration.Preparing += OnComponentPreparing;
    }

    static void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        var t = e.Component.Activator.LimitType;
        e.Parameters = e.Parameters.Union(new[] 
        { 
            new ResolvedParameter((p, i) => p.ParameterType == typeof(ILog), (p, i) => LogManager.GetLogger(t)) 
        });
    }
}

Затем я регистрирую модуль в моем методе Application_Start ASP.NET MVC:

protected void Application_Start()
{
     ContainerBuilder builder = new ContainerBuilder();
     builder.RegisterControllers(typeof (MvcApplication).Assembly) ;

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

     builder.RegisterModule(new LogInjectionModule());

     AreaRegistration.RegisterAllAreas();

     RegisterGlobalFilters(GlobalFilters.Filters);
     RegisterRoutes(RouteTable.Routes);
}

Я добавил к контроллеру конструктор, который принимает в качестве параметра ILog:

namespace MvcApplication6.Controllers
{
   public class HomeController : Controller
   {
      ILog _log;

      public HomeController(ILog logger) 
      {
         _log = logger;
      }

      public ActionResult Index()
      {
         ViewBag.Message = "Welcome to ASP.NET MVC!";

         _log.Info("Log message from Index()");

         return View();
      }

      public ActionResult About()
      {
         _log.Info("Log message from About()");

         return View();
      }
   }
}

Я уверен, что пропустил шаг, поэтому будем благодарны за любую помощь.


person RichardG    schedule 30.07.2011    source источник


Ответы (1)


Я не уверен, что это вызывает вашу проблему, но вам следует попробовать добавить модуль в ContainerBuilder до вызова builder.Build ();

Что-то вроде этого:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterControllers(typeof (MvcApplication).Assembly) ;
builder.RegisterModule(new LogInjectionModule());

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

Другой вариант - не вводить регистратор. Обычно, когда я разрабатываю класс, с зависимостями конструктора я пытаюсь выразить логические бизнес-зависимости компонента, который моделирую. Ведение журнала - это в основном деталь реализации, ортогональная приложению. По крайней мере, с log4net у вас может быть статический член в любом классе, где вам нужно вести журнал, который создается с помощью LogManager.GetLogger (type). Чтобы упростить добавление регистратора, вы можете использовать фрагмент кода Visual Studio.

person Iulian Margarintescu    schedule 31.07.2011
comment
Спасибо, перемещение RegisterModule перед вызовом builder.Build () решило проблему. Должен был это заметить. - person RichardG; 31.07.2011
comment
Я не мог не согласиться больше по поводу регистратора. Зачем вам отбрасывать всю доброту развязки, которую приносит DI, только потому, что логика ортогональна? Например. как вы можете правильно протестировать, если у вас есть статическая зависимость непосредственно от среды ведения журнала? Нет, ИМО, вы приносите сюда плохой совет. - person Peter Lillevold; 01.08.2011
comment
Я понимаю вашу точку зрения, но я думаю, что это дело вкуса. Меня лично не волнует развязка от фреймворка ведения журнала - и поскольку я использую почти исключительно инъекцию конструктора, я с радостью удалю любую зависимость, которая концептуально не требуется. При тестировании, вместо того, чтобы издеваться над регистратором, я просто считаю, что он просто работает, а в случае log4net он действительно просто работает. Как я уже сказал, я понимаю пуристское (если можно так сказать) представление о введении регистратора, и я не считаю это плохим подходом - я просто считаю, что проще использовать структуру ведения журнала напрямую. - person Iulian Margarintescu; 01.08.2011
comment
Мне нравится идея внедрения только бизнес-зависимостей через конструктор. То, что я думал, что я попытаюсь сделать, чтобы отделить фреймворк логгера, - это ввести логгер в свойство класса, а не использовать конструктор, хотя я, похоже, не могу заставить это работать, и читаю вики-страницу autofac не уверен, что это возможно для log4net при использовании модулей. - person RichardG; 02.08.2011
comment
Я также считаю, что это дело вкуса и действительно зависит от вас и вашей команды. - person ElvisLives; 03.08.2011