如何用温莎城堡覆盖一个组件? [英] How to overwrite a component with castle windsor?

查看:91
本文介绍了如何用温莎城堡覆盖一个组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在给定的Windsor容器中重新定义(默认)实现。那是OverWrite的目的吗?

I want to redefine an (default) implementation in a given windsor-container. Is that what OverWrite is for? Doesn't work, though.

container.Register(
                    Component.For<IServiceOperationAuthorization>()
                            .OverWrite()
                            .Instance(_authorization)
                    );

还有其他想法吗?

欢呼声,
Lars

cheers, Lars

推荐答案

我实际上找到了一个不错的解决方案,其中我将xml文件合并为覆盖,并使用流畅的注册作为默认值。

I actually found a nice solution where I combine xml-files for overrides and use fluent registrations for defaults.

fluent-API将impl的全名作为默认密钥。我在运行时会覆盖xml-config的ID,以模仿fluent-API的键约定。

The fluent-API takes the fullname of a impl as the default key. On the fly I override the id's of the xml-config to imitate the key-conventions of the fluent-API.

然后我在听 Kernel.ComponentRegistered 的同时注册xml-config。

Then i register the xml-config while I listen to Kernel.ComponentRegistered.

之后,我仅从xml尚未定义服务的代码配置中添加服务。

Afterwards I only add services from the code-config where the xml hasn't yet defined the service.

(有一段时间,我只是复制粘贴了代码。希望您能正常工作。如果发现任何问题,我会进行编辑)

IList<Type> unnamedServices = new List<Type>();
IDictionary<string, Type> namedServices = new Dictionary<string, Type>();

ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices);

container.Kernel.ComponentRegistered += registered;

// The method that captures the services
private static ComponentDataDelegate captureRegistrations(
    IList<Type> unnamedServices, IDictionary<string, Type> namedServices)
{
        return (key, handler) =>
               {
                   if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName)
                   {
                       unnamedServices.Add(handler.Service);
                   }
                   else
                   {
                       namedServices.Add(key, handler.Service);
                   }
               };
}

之后,在我在代码中注册服务之前,请检查它们是否已经存在注册。我还创建了一个基类,使此操作更加容易。这是一个应用程序配置:

After that before I register services in code, I check if they already have been registered. I also created a base class that makes this more easy. This is an application configuration:

public class ApplicationConfiguration : WindsorConfigurationSkeleton
{
    internal static WindsorServiceLocator create()
    {
        var container = createWith(null, "components-config.xml", coreServices, caches, roles);
        return new WindsorServiceLocator(container);
    }

    internal static IEnumerable<IRegistration> coreServices()
    {
        yield return Component.For<ISystemClock>()
            .ImplementedBy<PreciseSystemClock>()
            .Parameters(Parameter.ForKey("synchronizePeriodSeconds").Eq("10"))
            .LifeStyle.Singleton;

        yield return Component.For<IMailService>()
            .ImplementedBy<MailQueueService>()
            .LifeStyle.Singleton;
    }

    internal static IEnumerable<IRegistration> caches()
    {
        yield return Component.For<IDataCache<ServiceAttributes>>()
            .ImplementedBy<NoDataCache<ServiceAttributes>>()
            .LifeStyle.Singleton;

        // ....
    }
}

进行连接的基类:
(记录来自Commons.Logging)

The base class that does the wiring: (Logging is from Commons.Logging)

public class WindsorConfigurationSkeleton
{
    private static readonly ILog _log = LogManager.GetLogger(
        typeof(WindsorConfigurationSkeleton));

    internal static IWindsorContainer createWith(
        IRegistration[] customs, string configFile, params Func<IEnumerable<IRegistration>>[] methods)
    {
        IWindsorContainer container = new WindsorContainer();
        BugFix.Kernel = container.Kernel;

        container.AddFacility("factory.support", new FactorySupportFacility());

        IList<Type> unnamedServices = new List<Type>();
        IDictionary<string, Type> namedServices = new Dictionary<string, Type>();

        ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices);

        container.Kernel.ComponentRegistered += registered;

        if (customs != null)
        {
            container.Register(customs);
        }

        if (configFile != null)
        {
            tryAddXmlConfig(container, configFile);
        }

        container.Kernel.ComponentRegistered -= registered;

        if (methods != null && methods.Length > 0)
        {
            container.Register(union(unnamedServices, namedServices, methods));
        }

        return container;
    }

    private static ComponentDataDelegate captureRegistrations(
        IList<Type> unnamedServices, IDictionary<string, Type> namedServices)
    {
        return (key, handler) =>
               {
                   if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName)
                   {
                        var text = unnamedServices.Contains(handler.Service) ? "another" : "default";
                       _log.Info(
                           m => m(
                                    "Registered {2} service for {0} with {1}.",
                                    handler.Service.GetDisplayName(),
                                    handler.ComponentModel.Implementation.GetDisplayName(),
                                    text
                                    ));

                       unnamedServices.Add(handler.Service);
                   }
                   else
                   {
                        var text = namedServices.ContainsKey(key) ? "another" : "default";
                       _log.Info(
                           m => m(
                                    "Registered {3} service {0} with name '{1}' and {2}.",
                                    handler.ComponentModel.Service,
                                    handler.ComponentModel.Name,
                                    handler.ComponentModel.Implementation.GetDisplayName(),
                                    text
                                    ));
                       namedServices.Add(key, handler.Service);
                   }
               };
    }

    protected static void tryAddXmlConfig(IWindsorContainer container, string filename)
    {
        var fi = Resources.GetFileFromResourceHierarchy(typeof(ApplicationContext).Namespace, filename);
        if ( fi == null ) {
            return;
        }
        var configFile = fi.FullName;
        var xd = immitateFluentApiDefaultIdBehaviour(configFile);
        container.Install(Configuration.FromXml(new StaticContentResource(xd.OuterXml)));

    }

    private static XmlDocument immitateFluentApiDefaultIdBehaviour(string configFile)
    {
        var xd = new XmlDocument();
        xd.Load(configFile);

        foreach (
            XmlElement component in
                xd.SelectNodes("/configuration/components/component[@type and (not(@id) or @id = '')]"))
        {
            var type = Type.GetType(component.GetAttribute("type"), true);
            component.SetAttribute("id", type.FullName);
        }

        return xd;
    }

    private static IRegistration[] union(
        IList<Type> unnamed, IDictionary<string, Type> named, params Func<IEnumerable<IRegistration>>[] methods)
    {
        var all = new List<IRegistration>();
        foreach (var method in methods)
        {
            foreach (var registration in method())
            {
                var registrationType = registration.GetType();
                if (registrationType.IsGenericTypeOf(typeof(ComponentRegistration<>)))
                {
                    var componentType = registrationType.GetGenericArgumentsFor(typeof(ComponentRegistration<>))[0];

                    var name = (string)registrationType.GetProperty("Name").GetValue(registration, null);

                    if (name != null)
                    {
                        if (named.ContainsKey(name))
                        {
                            _log.Debug(
                                m => m("Skipped registering default named component {0}.", name));
                            continue;
                        }
                    }
                    else if (unnamed.Contains(componentType))
                    {
                        _log.Debug(
                            m => m("Skipped registering default component for type {0}.", componentType));
                        continue;
                    }

                    all.Add(registration);
                }
                else
                {
                    all.Add(registration);
                }
            }
        }

        return all.ToArray();
    }
}

这篇关于如何用温莎城堡覆盖一个组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆