Как изменить конфиги в Spring.Net - PullRequest
3 голосов
/ 24 декабря 2009

Преимущество контейнера IoC заключается в том, что вы можете поменяться имитацией службы в нижней части графа объектов. Однако в Spring.Net это сделать гораздо сложнее, чем в других контейнерах IoC. Вот некоторый код, который делает это в Unity и имеет код Spring.Net;

namespace IocSpringDemo
{
    using Microsoft.Practices.Unity;
    using NUnit.Framework;

    using Spring.Context;
    using Spring.Context.Support;

    public interface ISomeService
    {
        string DoSomething();
    }

    public class ServiceImplementationA : ISomeService
    {
        public string DoSomething()
        {
            return "Hello A";
        }
    }

    public class ServiceImplementationB : ISomeService
    {
        public string DoSomething()
        {
            return "Hello B";
        }
    }

    public class RootObject
    {
        public ISomeService SomeService { get; private set; }

        public RootObject(ISomeService service)
        {
            SomeService = service;
        }
    }

    [TestFixture]
    public class UnityAndSpringDemo
    {
        [Test]
        public void UnityResolveA()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<ISomeService, ServiceImplementationA>();
            RootObject rootObject = container.Resolve<RootObject>();
            Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
        }

        [Test]
        public void UnityResolveB()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<ISomeService, ServiceImplementationB>();
            RootObject rootObject = container.Resolve<RootObject>();
            Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
        }

        [Test]
        public void SpringResolveA()
        {
            IApplicationContext container = ContextRegistry.GetContext();
            RootObject rootObject = (RootObject)container.GetObject("RootObject");
            Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
        }

        [Test]
        public void SpringResolveB()
        {
            // does not work - what to do to make this pass?
            IApplicationContext container = ContextRegistry.GetContext();
            RootObject rootObject = (RootObject)container.GetObject("RootObject");
            Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
        }
    }
}

Для удобства Spring в файле App.config должно быть указано следующее. Понятно, что это только первый весенний тест, а не второй. Можете ли вы поместить несколько конфигураций пружин в файл конфигурации? Если да, то каков синтаксис и как вы к ним обращаетесь? Или есть другой способ сделать это?

  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>
  <spring>
    <context>
      <resource uri="config://spring/objects"/>
    </context>
    <objects xmlns="http://www.springframework.net">
      <object name="RootObject" type="IocSpringDemo.RootObject, IocDemo" autowire="constructor" />
      <object name="service" type="IocSpringDemo.ServiceImplementationA, IocDemo" autowire="constructor" />
    </objects>
  </spring>

Обновление

Вот частичный ответ, основанный на коде ссылки, которые Марко Лахма дал на блог Марка Поллака . У меня есть тесты, проходящие выше, со следующим кодом:

public static class SpringHelper
{
    public static T Resolve<T>(this IApplicationContext context, string name)
    {
        return (T)context.GetObject(name);
    }

    public static void RegisterType<T>(this GenericApplicationContext context, string name)
    {
        context.RegisterType(name, typeof(T));
    }

    public static void RegisterType(this GenericApplicationContext context, string name, Type type)
    {
        IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
        ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, type);
        builder.SetAutowireMode(AutoWiringMode.AutoDetect);

        context.RegisterObjectDefinition(name, builder.ObjectDefinition);
    }
}

...

    [Test]
    public void SpringResolveA()
    {
        GenericApplicationContext container = new GenericApplicationContext();
        container.RegisterType<RootObject>("RootObject");
        container.RegisterType<ServiceImplementationA>("service");

        RootObject rootObject = container.Resolve<RootObject>("RootObject");
        Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
    }

    [Test]
    public void SpringResolveB()
    {
        GenericApplicationContext container = new GenericApplicationContext();
        container.RegisterType<RootObject>("RootObject");
        container.RegisterType<ServiceImplementationB>("service");

        RootObject rootObject = container.Resolve<RootObject>("RootObject");
        Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
    }

Это вызывает у меня несколько вопросов:

  • Я хочу интегрировать эту технику в существующий код, который использует обычный контейнер. Почему я должен использовать другой тип контейнера, GenericApplicationContext в этом случае? Что если я захочу прочитать данные в этот объект из существующего весеннего конфига в app.config или web.config? Будет ли это работать в обычном контексте? Могу ли я тогда написать данные для этих регистраций с кодом?

  • Как я могу указать, что ISomeService должен быть создан как одиночный файл? Я не имею в виду предоставление экземпляра синглтона для контейнера, но контейнер для создания экземпляра, разрешения его конструктора и использования его при необходимости этого типа.

  • как я могу сделать эквивалент container.RegisterType<ISomeService, ServiceImplementationA>();? Я хочу зарегистрировать сопоставления типов для использования во всех случаях, когда этот тип нужен конструктору.

  • Что именно делает container.RegisterType<ServiceImplementationA>("service");? Кажется, что ServiceImplementationA регистрируется как реализация ISomeService, но ISomeService никогда не упоминается, поэтому может быть неоднозначность. например Что, если ServiceImplementationA реализовано более одного интерфейса.

  • Какое имя строки дается при регистрации? Он не будет работать с пустой строкой, но не имеет значения, что это такое.

Пытаюсь ли я использовать пружину так, чтобы она просто не работала? Я пытаюсь использовать его как другие контейнеры IoC, но он не совсем работает.

Ответы [ 2 ]

3 голосов
/ 13 января 2010

Добавление в качестве нового ответа, пытающегося обратиться к открытым точкам ...

Я хочу интегрировать эту технику в существующий код, который использует обычный контейнер. Почему я должен использовать другой тип контейнера, GenericApplicationContext в этом дело? Что делать, если я хочу прочитать данные в этот объект из существующей весны Конфиг в app.config или web.config? Будет ли это работать в обычном контексте? Могу ли я тогда написать данные по этим регистрации с кодом?

Spring имеет конкретные реализации контекста приложения для различных видов тактики инициализации. Наиболее распространенными из них являются GenericApplicationContext (руководство), XmlApplicationContext (файлы XML) и WebApplicationContext (очень похоже на XmlApplicationContext, но адаптированные для использования в Интернете). Все они реализуют общий интерфейс: IApplicationContext, который является предпочтительным способом доступа к этим контейнерам.

Неудобное изменение регистраций с помощью кода обычно означает, что вам нужно напрямую использовать конкретный подкласс. С GenericApplicationContext и StaticApplicationContext это вполне естественно, но XmlApplicationContext обычно считается только XML, и это «фиксируется» в определении XML.

Как я могу указать, что ISomeService быть создан как синглтон? Я не значит, поставлять единичный экземпляр контейнер, но контейнер для создать экземпляр, разрешив его конструктор, и использовать его, когда этот тип нужен.

Ваш SpringHelper делает именно это, по умолчанию все объекты в Spring являются одиночными. Вы можете изменить это поведение, вызвав метод SetSingleton ObjectDefinitionBuilder со значением false.

как я могу сделать эквивалент container.RegisterType (); ? я бы хотел сопоставления типов регистров для использования во всех случаи, когда этот тип нужен Конструктор.

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

Что именно делает container.RegisterType ( "обслуживание"); делать? Похоже на регистрацию ServiceImplementationA как реализация ISomeService, но ISomeService никогда не упоминается, поэтому может быть двусмысленность например что, если ServiceImplementationA реализовано более одного интерфейса.

Продолжая предыдущий ответ, здесь регистрируется синглтон типа ServiceImplementationA с именем «service». Этот объект поставляется с кандидатом на автоматическое подключение со всеми реализованными интерфейсами (и, конечно, с конкретным типом).

Какое имя строки дано регистрация для? Это не будет работать с en пустая строка, но это не кажется неважно, что это такое.

Это имеет большое значение, как объяснялось ранее. Имя является уникальным идентификатором в этом контексте (родительский контекст может иметь объект с тем же именем) и может использоваться для доступа к определенным регистрациям объектов. Вкратце, когда другие платформы могут ассоциировать тип как ключ к регистрации объекта, Spring использует name.

3 голосов
/ 24 декабря 2009

Сравнение яблок и апельсинов немного, поскольку в модульном тесте используется конфигурация кода для конфигурации Unity и XML (app.config) для Spring.NET.

Если вы пойдете по пути XML, то вы можете либо закомментировать старую реализацию A и определить реализацию B как используемую - что с настройкой все в порядке? Другой вариант - иметь выделенные XML-файлы для каждого сценария (настройка конфигурации) и включать их через определения ресурса контекста (теперь у вас есть встроенный ресурс). Другие опции включают файловую систему и сборку, , смотрите хороший пример в разделе веб-конфигурации в руководстве Spring.NET.

Если вы пойдете по пути настройки кода, я бы предложил проверить Spring.NET Recoil и предстоящий CodeConfig .

...