Как переписать компонент с замком Виндзор? - PullRequest
16 голосов
/ 18 марта 2009

Я хочу переопределить реализацию (по умолчанию) в данном windsor-контейнере. Для этого есть OverWrite? Не работает, хотя.

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

Любые другие идеи?

ура, Ларс

Ответы [ 6 ]

12 голосов
/ 30 мая 2013

Вы можете очень просто сделать это там, где вам нужно переопределить реализацию по умолчанию. Это пример из наших интеграционных тестов. Обе реализации теперь зарегистрированы, но ваш код будет использовать код по умолчанию, который вы только что зарегистрировали. Работает как бомба и не влияет на остальную часть приложения:

        var sendMailStub = MockRepository.GenerateStub<ISendMail>();
        _container.Register(
            Component
                .For<ISendMail>()
                .Instance(sendMailStub)
                .IsDefault()
            );
9 голосов
/ 20 марта 2009

Я согласен с Кшиштофом, что это обычно не очень хорошая идея ... Однако, насколько я могу сказать, OverWrite () не перезаписывает компонент по умолчанию, он просто перезаписывает образ жизни, определенный атрибутом (то есть [Singleton]).

Если вы хотите заменить компонент, вы можете использовать container.Kernel.RemoveComponent(string key) с последующей регистрацией нового компонента.

Вот пример , где это имеет смысл.

3 голосов
/ 29 октября 2009

Мне нужно было переключить реализацию компонента при запуске системы в наборе интеграционных тестов и не удалось использовать container.Kernel.RemoveComponent (). Так что я получил простое средство , которое позаботилось об этом для меня.

3 голосов
/ 22 марта 2009

Это будет проблема, которая может быть лучше решена путем установки контейнера с декоратором, где вы можете явно изменить реализацию, на которую декоратор направляет вызовы ... особенно если вы хотите заменить реализацию, которая существует компоненты (то есть синглтоны), которые могут существовать в течение всего срока действия вашего приложения.

Действительно нужно больше информации о том, чего вы пытаетесь достичь.


Подробнее о регистрации декораторов в Windsor .

1 голос
/ 21 августа 2010

Я действительно нашел хорошее решение, где я объединяю xml-файлы для переопределений и использую плавные регистрации для значений по умолчанию.

Fluent-API принимает полное имя impl в качестве ключа по умолчанию. На лету я переопределяю идентификаторы xml-config для имитации ключевых соглашений fluent-API.

Затем я регистрирую xml-config, пока слушаю Kernel.ComponentRegistered.

После этого я добавляю сервисы только из кода конфигурации, где xml еще не определил сервис.

(это было давно, и я просто скопировал код. Надеюсь, вы получите его на работу. Я внесу изменения, если вы обнаружите какие-либо проблемы)

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

После этого, прежде чем регистрировать службы в коде, я проверяю, были ли они уже зарегистрированы. Я также создал базовый класс, который делает это проще. Это конфигурация приложения:

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)

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();
    }
}
0 голосов
/ 19 марта 2009

Да, он переопределяет реализацию сервиса по умолчанию. Почему ты делаешь это? Почему бы не зарегистрировать это, а не переопределить?

Не могли бы вы предоставить больше контекста?

...