温莎城堡,依赖注入 return null

Castle Windsor, dependency injections return null

可能我的想法一开始就错了

我有一个 MVC5 项目,我想在我的网站和 EF 之间实现一个存储库层(简单来说,这是一个学习项目)。

我有一个 EF Code First 上下文和一个存储库 class:

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

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

然后我在第二层实现了额外的功能:

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

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

海豚是为我的所有上下文使用通用存储库,并在我的网站(日志记录、帐户管理等)中为不同的 areas/scopes 创建单独的上下文和单独的 "second layers",所以如果需要,我可以使用不同的数据库实现。

这是温莎实现:

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

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

并且... Logger 为空。为什么?

Logger 属性 需要 public.

完整文档here,相关详情为:

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.