Nodiink
Nodiink

Reputation: 360

Castle Windsor, dependency injections return null

Probably my idea is wrong from the beginning.

I have an MVC5 project, and I'm tring to implement a repository layer between my website and EF (for semplicity, it's a learning project).

I have an EF Code First Context, and a Repository class:

public interface IRepository<TDbContext> : IDisposable where TDbContext : class, new()

public class Repository<TContext> : IRepository<TContext>, IDisposable where TContext : DbContext, new()

Then I have a second layer where I implement additional functions:

public interface ILog<TLogContext> : IRepository<TLogContext> where TLogContext : class, new()

public class Logger<TContext> : Repository<TContext>, ILog<TContext> where TContext : LogContext, new()

The porpouse is to use the generic repository for all my contexts, and to create separate contexts and separate "second layers" for different areas/scopes inside my website (Logging, Account Management, etc), so I can use, if I want, different DB implementations.

And this is the Windsor implementation:

Installer.cs:

public class Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        // Controller
        container.Register(
            Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());

        // EF, Business
        container.Register(
            Component.For<IRepository<LogContext>>()
                     .ImplementedBy<Repository<LogContext>>()
                     .LifestylePerWebRequest()
        );

        container.Register(
            Component.For<ILog<LogContext>>()
                     .ImplementedBy<Logger<LogContext>>()
                     .LifestylePerWebRequest()
        );
    }
}

ControllerFactory.cs:

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(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
        }

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

And in Global.asax:

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        // Windsor
        container = new WindsorContainer().Install(FromAssembly.This());

        // ContainerFactory loading
        ControllerBuilder.Current.SetControllerFactory(new ControllerFactory(container.Kernel));
    }

BaseController.cs:

public class BaseController : Controller
{
    // Services
    internal ILog<LogContext> Logger { get; set; }

    public void Test()
    {
        var allEvents = Logger.All<Event>();
    }
}

And... Logger is null. Why?

Upvotes: 1

Views: 1188

Answers (1)

qujck
qujck

Reputation: 14580

The Logger property needs to be public.

Full documentation here, the relevant detail is:

Property injection of dependencies is designed to be done during component activation when a component is created. The responsibility of determining which properties are used for injection is fulfilled by default through PropertiesDependenciesModelInspector - a IContributeComponentModelConstruction implementation which uses all the following criteria to determine if a property represents a dependency:

  • Has 'public' accessible setter
  • Is an instance property
  • If ComponentModel.InspectionBehavior is set to PropertiesInspectionBehavior.DeclaredOnly, is not inherited
  • Does not have parameters
  • Is not annotated with the Castle.Core.DoNotWireAttribute attribute

If a property meets all these criteria, a dependency model is created for it, and this is then resolved when the component dependencies are resolved during activation.

Upvotes: 3

Related Questions