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 配置吗?如果是这样,语法是什么以及如何访问它们?或者还有其他方法可以做到这一点吗?
<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>
Update
这是基于代码的部分答案Marko Lahma 提供的 Mark Pollack 博客的链接。我通过了上述测试,代码如下:
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
but ISomeService
从未提及,因此可能存在歧义。例如如果什么ServiceImplementationA
实现了多个接口。
注册时指定的字符串名称是什么?它不适用于空字符串,但它是什么似乎并不重要。
我是否尝试以一种不起作用的方式使用 spring?我尝试像其他 IoC 容器一样使用它,但它不太有效。