7

Trying to use Autofac to inject a log4net class into my controller, but I get the following exception:

None of the constructors found with 'Public binding flags' on type 'MvcApplication6.Controllers.HomeController' can be invoked with the available services and parameters: Cannot resolve parameter 'log4net.ILog logger' of constructor 'Void .ctor(log4net.ILog)'.

I have created a module to inject the Log class using the correct type:

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)) }); } } 

I then register the module within my ASP.NET MVC Application_Start method:

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); } 

I have added a constuctor to the controller which takes an ILog as a parameter:

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(); } } } 

I am sure I have missed a step, so any help would be appreciated.

1 Answer 1

13

I'm not sure this is causing your problem but you should try to add the module to the ContainerBuilder before calling builder.Build();

Something like this:

ContainerBuilder builder = new ContainerBuilder(); builder.RegisterControllers(typeof (MvcApplication).Assembly) ; builder.RegisterModule(new LogInjectionModule()); var container = builder.Build() ; DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 

Another suggestion is to not inject the logger. Usually when i design a class, with the constructor dependencies i try to express the logical business dependencies of the component i'm modelling. Logging is mostly an implementation detail that is orthogonal to the application. At least with log4net you can have a static member in any class where you need logging that is created with LogManager.GetLogger(type). To facilitate adding the logger you can use a Visual Studio snippet.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, moving the RegisterModule before the call to builder.Build() sorted the problem out. Should have spotted that.
I could not disagree more regarding the logger. Why would you throw away all the decoupling goodness that DI brings just because the logic is orthogonal? E.g. how can you test properly if you have a static dependency directly to a logging framework? No, IMO you bring bad advice here.
I understand you point, but i think it's a mater of taste. I personally don't care much about decoupling form the logging framework - and since i use almost exclusively constructor injection, i'll gladly remove any dependency that is not conceptually required. When testing, instead of mocking the logger i just consider that it just works, and in case of log4net it actually does just work. As i said i understand the purist (if i may say) view of having the logger injected, and i don't consider it a bad approach - i just find it simpler to use the logging framework directly.
I do like the idea of having only business dependencies being injected via the constructor. What I thought I would try to do to decouple the logger framework was to inject the logger into a property on the class rather than use the constructor, although I don't seem to be able to get this to work, and reading the autofac wiki not sure it is possible for log4net when using modules.
I also think its a matter of taste and really depends on you and your team.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.