【问题标题】:Unity configuration with inheritance具有继承的 Unity 配置
【发布时间】:2015-10-15 17:35:06
【问题描述】:

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

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 加载统一配置,并在我们的产品代码和测试代码中使用它。

我们想要以下:

  • 对于生产场景,PrimaryClient 和 SecondaryClient 的类型应为 ServiceBusMessagingClient

  • 对于测试场景,PrimaryClient 和 SecondaryClient 的类型应为 MockMessagingClient

我们当前的统一配置如下:

<container name="azure">
 <register type="IMessagingClient" mapTo="FailoverMessagingClient"/>
</container>

我们是否必须使用一些拦截器来实现这一点?或者通过在 FailoverMessagingClient 中定义一个 ctor 并使用 ctor 注入?

一些建议会很棒!

【问题讨论】:

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


    【解决方案1】:

    您可以使用命名注册来做到这一点。

    例如,给定以下示例设置:

    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");
    

    【讨论】:

      【解决方案2】:

      使用统一容器时,您可以通过为不同的类再次注册来覆盖现有注册。

      例如:

      如果你运行这段代码:

      container.RegisterType<IMessagingClient, ServiceBusMessagingClient>();
      container.RegisterType<IMessagingClient, MockMessagingClient>();
      

      第一个注册被覆盖,因此IMessagingClient 映射到MockMessagingClient。就像第一行从未执行过。

      您可以使用这个事实,并在您的单元测试中(在您的测试类的排列阶段或设置方法中),只需像这样将IMessagingClient 注册到模拟实现中(在加载 XML 配置之后):

      container.RegisterType<IMessagingClient, MockMessagingClient>();
      

      顺便说一句,您可能不想在单元测试中使用 DI 容器。看看this question

      【讨论】:

        猜你喜欢
        • 2023-02-02
        • 2021-11-01
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        • 2018-02-09
        • 1970-01-01
        相关资源
        最近更新 更多