Castle Windsor Lifestyle配置

时间:2013-11-26 18:41:30

标签: inversion-of-control castle-windsor

我花了一些时间环顾四周,似乎没有一个明显的解决方案。

我从一个程序集中注册所有类型(大约有80种类型,接口在单独的程序集中)

    public static void RegisterAllFromAssemblies(string a)
    {
        IoC.Container.Register(
            AllTypes.FromAssemblyNamed(a)
                .Pick()
                .WithService.FirstInterface()
                .Configure(o => o.LifeStyle.PerWebRequest)
            );
    }

现在说如果我想为其中一个对象使用不同的LifeStyle,我无法覆盖,因为我将获得 已经为给定密钥注册了一个组件 错误。

我已经研究了在注册后修改生活方式的各种方法,但到目前为止还没有能够做任何事情。

这里应该是什么理想的解决方案?我不想放弃AllTypes功能。

我想我可以在注册所有内容时指定 .Where 过滤器并跳过一些手动注册的对象,但这不是一个非常有企业的解决方案..

2 个答案:

答案 0 :(得分:3)

我相信你所说的是在程序集中注册所有类型,其中程序集中的某些类型可能需要使用不同的生活方式进行注册。所以你有IRepository需要是一个PerWebRequest和ITypeMapper,它可以是一个单身。

我澄清,因为你也可能意味着你希望IRepository在你的代码中的一个位置是一个PerWebRequest而在另一个位置是一个单独的。在不创建疯狂生活方式的情况下,您可以创建组件并将其注册为默认生活方式。如果您有时需要另一种生活方式,您可以创建一个新组件并继承现有组件,仅用于注册(代码示例显示此情况,如果这令人困惑)。

我编写了示例,以便它适用于任何一种情况,我提供了几种不同的方法,所有方法都围绕着一次配置多个项目的过滤功能。

对于这个,我正在按类型调用特定组件的配置。它并不像你所说的那样“精力充沛”,但如果你只对规则有一些例外,那么意图就更清楚了。你会注意到你可以链接在一起配置。除非是必需的,因为第二个配置将为第一个配置选择组件,因为我唯一的条件是服务基于IService。这假设castle按顺序处理配置。我相信这个假设是合理的,但暂时没有看过来源。

container.Register(
    Classes.FromThisAssembly()
        .BasedOn<IService>()
        .ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
        .Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));

这个使用属性更普遍地偏离正常的生活方式“PerWebRequest

container2.Register(
    Classes.FromThisAssembly()
        .BasedOn<IService>()
        .ConfigureIf(
            //condition to check - do we have our custom Attribute?
            registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
            //if true register as singleton
            component => component.LifestyleSingleton(),
            //else register as per web request
            component => component.LifestylePerWebRequest()
            ));

现在我已经给了你一些解决你眼前问题的样本(据我所知)让我免费提供你的建议!

首先,我不喜欢WithService.FirstInterface()。正如智能感知所说,当你实现多个接口时,它是不确定的。任何开发人员都可以进入并对类进行无害的接口更改,然后破坏系统。如果您可以使用WithService.DefaultInterfaces(),那么您将更难以解决问题。默认接口只是告诉城堡,在注册Foo组件时,如果它实现了一个名为IFoo的接口,则使用服务IFoo。

其次,我相信如果你将注册逻辑划分为内聚单元,你可能不会遇到这个问题。关键是要有许多实现IWindsorInstaller的安装程序文件。在这些安装程序内部,您只能注册(使用类或类型以保持企业仍然存在)对特定安装程序有意义的类型。您在同一个安装程序中有多种生活方式问题的可能性非常低(如果您发现这一点,则可能需要更多安装程序)

如果您遵循这种方法,最终可能会得到RepositoryInstaller,ViewInstaller,ControllerInstaller等。More on installers can be found on the castle documentation site

如果您需要,可以执行的操作是为您的所有系统提供一个通用的boostrapper,它可以查看应用程序目录并安装目录中的所有安装程序。因为这不是你要求的我会停止详细说明,但如果有兴趣你可以ping我,我可以告诉你更多我正在谈论的内容。

作为控制台应用的完整示例代码:

using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MultipleLifecyles
{
    [AttributeUsage(AttributeTargets.Class)]
    public class ShouldBeSingleton : Attribute
    {
    }

    public interface IService
    {
        void DoSomething();
    }

    public class MyComponent : IService
    {
        public void DoSomething()
        {
            throw new NotImplementedException();
        }
    }

    [ShouldBeSingleton]
    public class MyComponentAsSingleton : MyComponent
    {

    }

    class Program
    {
        static void Main(string[] args)
        {

            //option 1
            IWindsorContainer container = new WindsorContainer();

            container.Register(
                Classes.FromThisAssembly()
                    .BasedOn<IService>()
                    .ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
                    .Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));

            IWindsorContainer container2 = new WindsorContainer();

            container2.Register(
                Classes.FromThisAssembly()
                    .BasedOn<IService>()
                    .ConfigureIf(
                        //condition to check - do we have our custom Attribute?
                        registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
                        //if true register as singleton
                        component => component.LifestyleSingleton(),
                        //else register as per web request
                        component => component.LifestylePerWebRequest()
                        ));


            Console.ReadLine();
        }
    }
}

答案 1 :(得分:1)

您可以先选择手动注册例外吗?如果是这样,手动注册的组件将不会被“AllTypes”重新注册(我建议你改用Classes)。 如果在“组”注册后手动注册组件,则会抛出异常,但反之亦然。

例如

//YourImplementation lives in assembly 'a'
IoC.Container.Register(
    Component.For<YourInterface>().ImplementedBy<YourImplementation>().LifestyleSingleton()
    );

IoC.Container.Register(
    Classes.FromAssemblyNamed(a)
        .Pick()
        .WithService.FirstInterface()
        .Configure(o => o.LifeStyle.PerWebRequest)
    );