Como alterar as configurações no Spring.Net

Uma vantagem de um contêiner IoC é que você pode trocar um serviço simulado na parte inferior do gráfico do objeto. No entanto, isso parece muito mais difícil de fazer em Spring.Net do que em outros contêineres IoC. Aqui está um código que faz isso no Unity e tem o código 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());
        }
    }
}

Para o benefício do Spring, o seguinte precisava estar no arquivo App.config. Claramente isso só serve o primeiro teste de primavera, e não o segundo. Você pode colocar várias configurações de mola no arquivo de configuração? Se sim, qual é a sintaxe e como você os acessa? Ou existe outra maneira de fazer isso?

  <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>
Atualizar

Aqui está uma resposta parcial com base no código emos links que Marko Lahma deu ao blog de Mark Pollack. Eu tenho os testes acima passando, com o seguinte código:

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

Isso levanta algumas questões para mim:

Eu quero integrar essa técnica no código existente que usa o contêiner usual. Por que preciso usar um tipo de contêiner diferente?GenericApplicationContext nesse caso? E se eu quiser ler dados nesse objeto a partir da configuração de mola existente em app.config ou web.config? Funcionaria como o contexto usual? Eu poderia então gravar dados sobre esses registros com código?

Como posso especificar issoISomeService deve ser criado como um singleton? Não me refiro a fornecer uma instância singleton ao contêiner, mas o contêiner para criar a instância, resolver seu construtor e usá-la quando esse tipo for necessário.

como posso fazer o equivalente acontainer.RegisterType<ISomeService, ServiceImplementationA>(); ? Eu quero registrar mapeamentos de tipo para usar em todos os casos em que esse tipo é necessário por um construtor.

O que exatamente fazcontainer.RegisterType<ServiceImplementationA>("service"); Faz? Parece se registrarServiceImplementationA como a implementação deISomeService masISomeServicenunca é mencionado, então pode haver ambigüidade. por exemplo. e seServiceImplementationA implementou mais de uma interface.

Qual é o nome da string dado ao registro? Não vai funcionar com uma string vazia, mas não parece importar o que é.

Estou tentando usar a primavera de uma forma que simplesmente não funciona? Eu estou tentando usá-lo como outros contêineres IoC, mas não está funcionando bem.

questionAnswers(2)

yourAnswerToTheQuestion