如何在 Spring.Net 中更改配置 [英] How to change configs in Spring.Net

查看:32
本文介绍了如何在 Spring.Net 中更改配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

IoC 容器的一个优点是您可以在对象图底部交换模拟服务.然而,这在 Spring.Net 中似乎比在其他 IoC 容器中更难做到.下面是一些在 Unity 中执行并具有 Spring.Net 代码的代码;

An advantage of an IoC container is that you can swap in a mock service at the bottom of your object graph. However this seems much harder to do in Spring.Net than in other IoC Containers. Here's some code that does it in Unity and has Spring.Net code;

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 文件中需要包含以下内容.显然,这仅适用于第一次弹簧测试,而不适用于第二次.您可以在配置文件中放置多个弹簧配置吗?如果是这样,语法是什么以及如何访问它们?或者有其他方法可以做到这一点?

For the benefit of Spring, the following needed to be in the App.config file. Clearly this only serves the first spring test, and not the second. Can you put multiple spring configurations in the config file? If so, what is the syntax and how do you access them? Or is there another way to do this?

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

<小时>

更新

这是基于代码的部分答案 Marko Lahma 提供给 Mark Pollack 博客的链接.我通过了上述测试,代码如下:


Update

Here is a partial answer based at code at the links that Marko Lahma gave to Mark Pollack's blog. I have the above tests passing, with the following code:

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

这向我提出了几个问题:

This raises a few questions to me:

  • 我想将此技术集成到使用常用容器的现有代码中.在这种情况下,为什么我必须使用不同的容器类型 GenericApplicationContext?如果我想从 app.config 或 web.config 中现有的 spring 配置将数据读入这个对象怎么办?它会像通常的上下文一样工作吗?然后我可以用代码在这些注册上写数据吗?

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

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

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.

我怎样才能做到 container.RegisterType(); 的等价物?我想注册类型映射以在构造函数需要该类型的所有情况下使用.

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

container.RegisterType("service"); 究竟是做什么的?似乎将 ServiceImplementationA 注册为 ISomeService 的实现,但从未提及 ISomeService,因此可能存在歧义.例如如果 ServiceImplementationA 实现了多个接口会怎样.

What exactly does container.RegisterType<ServiceImplementationA>("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.

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

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 容器一样使用它,但效果不佳.

Am I trying to use spring in a way that it just does not work? I'm trying to use it like other IoC containers, but it's not quite working.

推荐答案

添加为新答案试图解决开放点...

Adding as new answer trying to address the open points...

我想整合这个技术到使用通常的现有代码容器.为什么我必须使用不同的容器类型,GenericApplicationContext 在这个案件?如果我想将数据读入怎么办这个对象来自现有的弹簧在 app.config 或 web.config 中配置?它会像通常的上下文一样工作吗?然后我可以在这些上面写数据吗用代码注册?

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 使用量身定制).它们都实现了通用接口:IApplicationContext,这是访问这些容器的首选方式.

Spring has concrete application context implementations for different kind of initialization tactics. The most common ones to use are GenericApplicationContext (manual), XmlApplicationContext (XML files) and WebApplicationContext (very much like XmlApplicationContext but tailored for web use). They all implement common interface: IApplicationContext which is the preferred way to access these containers.

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

Unfortonately altering registrations with code usually means that you need to use the specific sub-class directly. With GenericApplicationContext and StaticApplicationContext this is quite natural but XmlApplicationContext is usually considered to be XML only and this ways "fixed" to XML definition.

如何指定 ISomeService 是要创建为单例?我不意味着提供一个单例实例容器,但容器创建实例,解析其构造函数,并在该类型时使用它需要.

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 方法来改变这种行为.

Your SpringHelper does just that, by default all objects in Spring are singletons. You could alter this behavior by calling ObjectDefinitionBuilder's SetSingleton method with false.

我怎样才能做到相当于容器.RegisterType();?我想要注册类型映射以用于所有需要该类型的情况构造函数.

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)来区分不同的实现.因此,如果您想获得特定类型来为特定实例提供服务,以防有许多替代方案,您应该按名称引用此特定实例.如果您使用自动装配并且您的对象依赖于接口 ISomeService 并且只有一个注册的对象实现了它,那么自动装配可以毫无歧义地设置它.

Spring uses object names (ids) to distinct between different implementations. So if you want to get specific type to serve a specific instance in case that there are many alternatives you should refer to this specific instance by name. If you are using autowiring and your object has dependency to interface ISomeService and there's only one object registered that implements it, the autowiring can set it without ambiguity.

究竟是做什么的container.RegisterType("服务");做?好像注册了ServiceImplementationA 作为ISomeService 的实现但是ISomeService 从未被提及,所以可能会有歧义.例如如果ServiceImplementationA 已实现多个界面.

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 类型的单例.这个对象是自动装配的候选对象及其所有实现的接口(当然还有它的具体类型).

Continuing from previous answer, this registers singleton of type ServiceImplementationA with name "service". This object comes autowiring candidate with all it's implemented interfaces (and with it's concrete type of course).

给定的字符串名称是什么注册?它不会与en 空字符串,但似乎没有不管它是什么.

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.

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

It matters a great deal as explained earlier. The name is unique id within that context (parent context could have object with same name) and can be used to access specific object registrations. In short where other frameworks may associate a type as key to object registration, Spring uses name.

这篇关于如何在 Spring.Net 中更改配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆