我有一个简单的类结构,接口如下:
public interface IMessagingClient (interface supporting service bus queue operation)
public class ServiceBusMessagingClient : IMessagingClient (real implementation)
public class MockMessagingClient : IMessagingClient (mock implementation for our unit test)
public class FailoverMessagingClient : IMessagingClient (this implementation internally uses 2 clients and switches roles b/w 2 as and when disaster in a datacenter occur)
{
private IMessagingClient PrimaryClient { get; set; }
private IMessagingClient SecondaryClient { get; set; }
}
我们从web.config / app.config加载unity config,并在我们的产品代码和测试代码中使用它。
我们想要关注:
对于生产方案,PrimaryClient和SecondaryClient应为ServiceBusMessagingClient类型
对于测试场景,PrimaryClient和SecondaryClient应为MockMessagingClient类型
我们当前的统一配置如下:
<container name="azure">
<register type="IMessagingClient" mapTo="FailoverMessagingClient"/>
</container>
我们是否必须使用一些拦截器来实现这一目标?或者通过在FailoverMessagingClient中定义ctor并使用ctor注入?
一些建议会很棒!
答案 0 :(得分:2)
您可以使用命名注册来执行此操作。
例如,给出以下示例设置:
namespace ConsoleApplication8
{
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
public interface IMessagingClient { }
public class ServiceBusMessagingClient : IMessagingClient { }
public class MockMessagingClient : IMessagingClient { }
public class FailoverMessagingClient : IMessagingClient
{
private readonly IMessagingClient primaryClient;
private readonly IMessagingClient secondaryClient;
public FailoverMessagingClient(IMessagingClient primaryClient, IMessagingClient secondaryClient)
{
this.primaryClient = primaryClient;
this.secondaryClient = secondaryClient;
}
}
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer().LoadConfiguration();
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
}
}
}
您可以使用app.config
连接依赖项<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IMessagingClient" type="ConsoleApplication8.IMessagingClient, ConsoleApplication8" />
<alias alias="ServiceBusMessagingClient" type="ConsoleApplication8.ServiceBusMessagingClient, ConsoleApplication8" />
<alias alias="MockMessagingClient" type="ConsoleApplication8.MockMessagingClient, ConsoleApplication8" />
<alias alias="FailoverMessagingClient" type="ConsoleApplication8.FailoverMessagingClient, ConsoleApplication8" />
<container>
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
<register type="IMessagingClient" name="Two" mapTo="FailoverMessagingClient">
<constructor>
<param name="primaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
<param name="secondaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
</constructor>
</register>
</container>
</unity>
</configuration>
更改行
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
到
<register type="IMessagingClient" name="One" mapTo="MockMessagingClient" />
允许您根据需要更换IMessagingClient的实现。
就个人而言,我宁愿使用流畅的语法
来做这件事 var container = new UnityContainer();
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>("One");
container.RegisterType<IMessagingClient, FailoverMessagingClient>("Two",
new InjectionConstructor(new ResolvedParameter<IMessagingClient>("One"), new ResolvedParameter<IMessagingClient>("One")));
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
答案 1 :(得分:0)
使用统一容器时,您可以通过再次为其他类注册来覆盖现有注册。
例如:
如果您运行此代码:
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>();
container.RegisterType<IMessagingClient, MockMessagingClient>();
第一次注册被覆盖,因此IMessagingClient
被映射到MockMessagingClient
。就像第一行从未执行过一样。
您可以使用此事实,并在单元测试中(在测试类的排列阶段或设置方法中),只需将IMessagingClient
注册到模拟实现(如下所示)(加载XML配置后) ):
container.RegisterType<IMessagingClient, MockMessagingClient>();
顺便说一下,您可能不想在单元测试中使用DI容器。看看this question。