Как перезаписать компонент с виндзором замка?

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

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

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

веселит, Ларс

Ответы

Ответ 1

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

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

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

Впоследствии я добавляю только службы из кода-config, где 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();
    }
}

Ответ 2

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

        var sendMailStub = MockRepository.GenerateStub<ISendMail>();
        _container.Register(
            Component
                .For<ISendMail>()
                .Instance(sendMailStub)
                .IsDefault()
            );

Ответ 3

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

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

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

Ответ 4

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

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


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

Ответ 5

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

Ответ 6

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

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