So ändern Sie die Konfiguration in Spring.Net

Ein Vorteil eines IoC-Containers besteht darin, dass Sie einen Schein-Service am unteren Rand Ihres Objektgraphen austauschen können. Dies scheint jedoch in Spring.Net viel schwieriger zu sein als in anderen IoC-Containern. Hier ist ein Code, der dies in Unity ausführt und Spring.Net-Code enthält.

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

Für Spring musste sich Folgendes in der Datei App.config befinden. Dies dient eindeutig nur dem ersten Frühlingstest und nicht dem zweiten. Können Sie mehrere Federkonfigurationen in die Konfigurationsdatei einfügen? Wenn ja, wie lautet die Syntax und wie greifen Sie darauf zu? Oder gibt es einen anderen Weg, dies zu tun?

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

Hier ist eine Teilantwort basierend auf Code unterdie Links, die Marko Lahma zu Mark Pollacks Blog gegeben hat. Ich habe die obigen Tests mit dem folgenden Code bestanden:

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

Dies wirft ein paar Fragen an mich auf:

Ich möchte diese Technik in vorhandenen Code integrieren, der den üblichen Container verwendet. Warum muss ich einen anderen Containertyp verwenden,GenericApplicationContext in diesem Fall? Was ist, wenn ich Daten aus der vorhandenen Spring-Konfiguration in app.config oder web.config in dieses Objekt einlesen möchte? Würde es wie gewohnt funktionieren? Könnte ich dann mit Code Daten über diese Registrierungen schreiben?

Wie kann ich das spezifizieren?ISomeService soll als singleton erstellt werden? Ich meine nicht, dem Container eine Singleton-Instanz bereitzustellen, sondern den Container, um die Instanz zu erstellen, ihren Konstruktor aufzulösen und sie zu verwenden, wenn dieser Typ benötigt wird.

Wie kann ich das Äquivalent voncontainer.RegisterType<ISomeService, ServiceImplementationA>(); ? Ich möchte Typzuordnungen registrieren, die in allen Fällen verwendet werden, in denen dieser Typ von einem Konstruktor benötigt wird.

Was genau machtcontainer.RegisterType<ServiceImplementationA>("service"); tun? Es scheint sich zu registrierenServiceImplementationA als die Umsetzung vonISomeService aberISomeServicewird nie erwähnt, daher kann es zu Mehrdeutigkeiten kommen. z.B. was, wennServiceImplementationA implementiert mehr als eine Schnittstelle.

Wofür wird der Stringname bei der Registrierung angegeben? Es wird nicht mit einer leeren Zeichenkette funktionieren, aber es scheint egal zu sein, was es ist.

Versuche ich, den Frühling so zu nutzen, dass er einfach nicht funktioniert? Ich versuche, es wie andere IoC-Container zu verwenden, aber es funktioniert nicht ganz.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage