ioc-container - 如何在 Spring.Net 中更改配置

标签 ioc-container app-config configuration-files spring.net

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 文件中。显然,这仅适用于第一个 Spring 测试,而不适用于第二个。能不能在config文件里放多个spring的配置?如果是这样,语法是什么以及如何访问它们?或者还有其他方法吗?

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

更新

这是基于代码的部分答案 the links that Marko Lahma gave to Mark Pollack's blog .我已经通过了上述测试,代码如下:

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 中现有的 spring 配置中将数据读入这个对象怎么办?它会像通常的上下文一样工作吗?然后我可以用代码在这些注册上写入数据吗?

  • 如何指定 ISomeService是作为单例创建的吗?我的意思不是向容器提供单例实例,而是容器创建实例、解析其构造函数并在需要该类型时使用它。

  • 我怎样才能做相当于 container.RegisterType<ISomeService, ServiceImplementationA>(); 的事情? ?我想注册类型映射,以便在构造函数需要该类型的所有情况下使用。

  • 到底是什么container.RegisterType<ServiceImplementationA>("service");做?好像注册ServiceImplementationA作为 ISomeService 的实现但是ISomeService从未被提及,因此可能存在歧义。例如如果ServiceImplementationA怎么办实现了不止一个接口(interface)。

  • 注册的字符串名称是什么?它不适用于空字符串,但它是什么似乎无关紧要。

我是否尝试以一种它无法正常工作的方式使用 spring?我正在尝试像使用其他 IoC 容器一样使用它,但效果不佳。

最佳答案

添加为新答案试图解决 Unresolved 问题...

I want to integrate this technique into existing code that uses the usual container. Why do I have to use a different container type, GenericApplicationContext in this case? What if I want to read data into this object from the existing spring config in app.config or web.config? Would it work as the usual context? Could I then write data over these registrations with code?

Spring 为不同类型的初始化策略提供了具体的应用程序上下文实现。最常用的是 GenericApplicationContext(手动)、XmlApplicationContext(XML 文件)和 WebApplicationContext(非常像 XmlApplicationContext,但专为 web 使用而定制)。它们都实现了通用接口(interface):IApplicationContext,这是访问这些容器的首选方式。

不幸的是,用代码更改注册通常意味着您需要直接使用特定的子类。对于 GenericApplicationContext 和 StaticApplicationContext,这是很自然的,但 XmlApplicationContext 通常被认为只是 XML,并且这种方式“固定”为 XML 定义。

How can I specify that ISomeService is to be created as a singleton? I don't mean supply a singleton instance to the container, but the container to create the instance, resolving its constructor, and use it when that type is needed.

您的 SpringHelper 就是这样做的,默认情况下,Spring 中的所有对象都是单例。您可以通过使用 false 调用 ObjectDefinitionBuilder 的 SetSingleton 方法来更改此行为。

how can I do the equivalent of container.RegisterType(); ? I want to register type mappings to use in all cases where that type is needed by a constructor.

Spring 使用对象名称 (id) 来区分不同的实现。因此,如果您希望获得特定类型来为特定实例提供服务,以防万一有很多选择,您应该按名称引用该特定实例。如果您正在使用 Autowiring 并且您的对象依赖于接口(interface) ISomeService 并且只有一个注册的对象实现它,则 Autowiring 可以毫无歧义地设置它。

What exactly does container.RegisterType("service"); do? It seems to register ServiceImplementationA as the implementation of ISomeService but ISomeServiceis never mentioned, so there could be ambiguity. e.g. what if ServiceImplementationA implemented more than one interface.

从之前的回答继续,这注册了名为“service”的 ServiceImplementationA 类型的单例。这个对象带有它所有实现的接口(interface)(当然还有它的具体类型)。

What is the string name given to the registration for? It won't work with en empty string, but it doesn't seem to matter what it is.

如前所述,它非常重要。该名称是该上下文中的唯一标识(父上下文可以具有同名对象),可用于访问特定对象注册。简而言之,在其他框架可能将类型关联为对象注册的键的情况下,Spring 使用名称。

关于ioc-container - 如何在 Spring.Net 中更改配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1955862/

相关文章:

java - Spring Java 配置中的别名定义

.net - StructureMap 和注入(inject) IEnumerable<T>

c# - 扩展类的依赖注入(inject)?

asp.net - CaSTLe.Core 信任级别问题

msbuild - 我可以使用 msbuild 更新非 xml 配置文件吗?

node.js - 如何在 Node.js 中指定不同的配置文件?

asp.net-mvc-3 - MVC2 到 MVC3 IOC 问题

c# - 从另一个文件加载部分 App.Config

c# winapp 将 app.config 添加到安装程序?

c# - 为什么 config.Appsettings.Settings ["MySetting"].Value 在 Windows 7 中失败,但在其他版本中没有