带继承的Unity配置

时间:2015-10-15 17:35:07

标签: c# inversion-of-control unity-container

我有一个简单的类结构,接口如下:

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注入?

一些建议会很棒!

2 个答案:

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