2
votes

I'm working out this(http://docs.castleproject.org/Windsor.Windsor-Tutorial-Part-Five-Adding-logging-support.ashx) IoC tutorial in Castle Windsor, I have passed all of the previous steps and as in above tutorial I'm trying to get the log4net logger injected into my controller via property, like following:

public class HomeController : Controller
{
    // this is Castle.Core.Logging.ILogger, not log4net.Core.ILogger
    public ILogger Logger { get; set; }

    public ActionResult Index()
    {
        Logger.Debug("Hello world");

        ViewBag.Message = "Hello world";

        return View();
    }

}

but unfortunately at point of execution of Logger.Debug Logger is null, so that results with null reference exception. Though when I'm trying to call

var logger = container.Resolve<ILogger>();

logger.Debug("Container bootstrapped");

inside Global.asax logger is perfectly resolved.

Why does Windsor doesn't want to resolve dependency inside controller?


EDIT

Controller is created via Windsor

Global.asax

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Castle.Core.Logging;
using Castle.Windsor;
using Castle.Windsor.Installer;
using FlightManagementSystem.WebPlatform.Configuration.IoC.Windsor.Factories;

namespace FlightManagementSystem.WebPlatform
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        private static IWindsorContainer container;

        protected void Application_Start()
        {
            Debugger.Break();

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

            container = new WindsorContainer();

            container.Install(FromAssembly.This());

            var controllerFactory = new ControllerFactory(container.Kernel);

            ControllerBuilder.Current.SetControllerFactory(controllerFactory);

        }

        protected void Application_End()
        {
            container.Dispose();
        }
    }
}

ControllerFactory.cs

using System;
using System.Web;
using System.Web.Mvc;
using Castle.MicroKernel;

namespace FlightManagementSystem.WebPlatform.Configuration.IoC.Windsor.Factories
{
    public class ControllerFactory : DefaultControllerFactory
    {
        private readonly IKernel kernel;

        public ControllerFactory(IKernel kernel)
        {
            this.kernel = kernel;
        }

        public override void ReleaseController(IController controller)
        {
            kernel.ReleaseComponent(controller);
        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                throw new HttpException(404, String.Format(Resources.THE_CONTROLLER_FOR_PATH_0_COULD_NOT_BE_FOUND, requestContext.HttpContext.Request.Path));
            }

            return (IController) kernel.Resolve(controllerType);
        }
    }
}

ControllerInstaller.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace FlightManagementSystem.WebPlatform.Configuration.IoC.Windsor.Installers
{
    public class ControllerInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register
            (
                Classes.FromThisAssembly()
                .BasedOn<IController>()
                .LifestyleTransient()
            );
        }
    }
}

LoggerInstaller.cs

using Castle.Facilities.Logging;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace FlightManagementSystem.WebPlatform.Configuration.Logger.log4net
{
    public class LoggerInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.AddFacility<LoggingFacility>(f => f.UseLog4Net());
        }
    }
}
1
How do you create the controller?Krzysztof Kozmic
Controller is created via Windsor, I've edited main question, inserted the controller creation logicLu4
Clean the solution and recompile it, see if that helps. Your code is fine. THe problem lies in the environment.Krzysztof Kozmic
It seems that previously I had the public ILogger Logger { get; private set; } statement instead of public ILogger Logger { get; set; } one, that's why it didn't workLu4
There is a cleaner way of adding a dependency resolver in mvc 4 here is a full example with ninject gist.github.com/ower89/5565205 implement System.Web.Mvc.IDependencyResolver for injections in mvc controllers and System.Web.Http.Dependencies.IDependencyResolver for injections in apicontrollers.Remo H. Jansen

1 Answers

3
votes

It is not really answer to your problem, but a few suggestions:

1) Use null object patter to prevent NRE when logging:

ILogger logger = NullLogger.Instance;
public ILogger Log
{
    get { return logger; }
    set { logger = value ?? NullLogger.Instance; }
}

2) Logging facility should be added in most cases at first - before any installers are registered:

container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.UseLog4Net());
container.Install(FromAssembly.This());

If you add logging facility later you can lost some valuable messages during installation.