【问题标题】:Unregister service from unity从统一注销服务
【发布时间】:2017-10-11 12:56:29
【问题描述】:

我在我的应用程序中使用 Unity。对于一项集成测试,我们想要更改注册到应用程序的服务之一(因为它需要一些硬件)。

所以,我可以注册新的“模拟”类型,但我无法删除为此接口注册的其他实现。

另外提一下,目前我们注册了这个接口的“列表”(它是某种驱动程序),我们想删除所有其他实例。

知道我该怎么做吗?

【问题讨论】:

  • @aelbouachri 嗨,我已经读过这个,但是由于在实际应用中,这需要是一个单例,我不能这样做。
  • @J4N 如果它是一个集成测试,那么在安排/设置测试时不要注册不需要的类型。如果没有minimal reproducible example,就无法提供太多帮助/建议。
  • @NKosi:我们在 app.config 中配置了所有这些,我希望拥有完全相同的模块,除了我们必须模拟的模块。这样可以确保如果有一天我们因为添加了错误的实现而引入了回归,我们的测试将会失败。
  • 听起来您正试图在生产应用程序和测试应用程序之间重用composition root。如果您避免使用composition root reuse,整个问题就会消失。从理论上讲,这听起来像是通过重用相同的配置获得了一些东西,但实际上它很少值得。组合根您的应用程序配置。您的测试应用程序是一个不同的应用程序,因此应该有自己的组合根。

标签: c# .net dependency-injection unity-container


【解决方案1】:

您可以简单地使用模拟或空白实现覆盖注册。在命名注册的情况下,只要您使用相同的名称注册,它就会起作用。当您添加新注册时,Unity 将忽略以前的注册。

在我们的 UnitTesting 项目中,我们目前添加了所有常规注册,然后在设置中我们在它们之上注册模拟。

【讨论】:

    【解决方案2】:

    我假设您没有在测试中使用 Container.IsRegistered(这并不总是一个有效的假设)。

    与@Tipx 答案类似的方法是重新注册,但提供InjectionMember 将清除与该类型关联的所有策略。这样做的好处是,由于策略配置已被删除,Unity 应该像从未注册过的类型一样工作(即使它们会出现在注册列表中)。

    这是清除策略的InjectionMember ClearAllPolicies:

    public class ClearAllPolicies : InjectionMember
    {
        public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
        {
            var serviceTypeBuildKey = new NamedTypeBuildKey(serviceType, name);
            policies.Clear<IBuildKeyMappingPolicy>(serviceTypeBuildKey);
    
            var buildKey = new NamedTypeBuildKey(implementationType, name);
    
            policies.Clear<IBuildKeyMappingPolicy>(buildKey);
            policies.Clear<IConstructorSelectorPolicy>(buildKey);
            policies.Clear<IBuildPlanCreatorPolicy>(buildKey);
            policies.Clear<IBuildPlanPolicy>(buildKey);
            policies.Clear<IMethodSelectorPolicy>(buildKey);
            policies.Clear<IPropertySelectorPolicy>(buildKey);
            policies.Clear<ILifetimeFactoryPolicy>(buildKey);
            policies.Clear<ILifetimePolicy>(buildKey);
            policies.Clear<IBuilderPolicy>(buildKey);
    
            DependencyResolverTrackerPolicy.RemoveResolvers(policies, buildKey);
        }
    }
    

    这是一个示例,其中注册了 3 个 ILogger 命名实现并解析了 ILoggers 列表。然后为记录器清除策略并进行检查以确保无法解析ILogger

    IUnityContainer container = new UnityContainer();
    
    container.RegisterType<ILogger, MyLogger>("Logger1");
    container.RegisterType<ILogger, MyLogger>("Logger2");
    container.RegisterType<ILogger, MyLogger>("Logger3");
    
    // Resolve list of all loggers
    var loggers = container.Resolve<ILogger[]>();
    
    // Remove Policies for all ILoggers using ClearAllPolicies
    foreach (var registration in container.Registrations
                                          .Where(r => r.RegisteredType == typeof(ILogger)))
    {
        container.RegisterType(
           registration.RegisteredType,
           registration.MappedToType, 
           registration.Name, 
           new ClearAllPolicies());
    }
    
    // Ensure that when we try to resolve an ILogger or list of ILogger's that
    // an exception is thrown
    Assert.Throws<ResolutionFailedException>(() => container.Resolve<ILogger>("Logger1"));
    Assert.Throws<ResolutionFailedException>(() => container.Resolve<ILogger>("Logger2"));
    Assert.Throws<ResolutionFailedException>(() => container.Resolve<ILogger>("Logger3"));
    Assert.Throws<ResolutionFailedException>(() => container.Resolve<ILogger[]>());
    

    注意事项和警告

    • 不要在生产代码中使用它——我只会将它用于测试目的
    • 这可能无法捕获所有适用的策略,并且不完整或不适用于所有边缘情况(例如拦截或其他深奥的场景)

    【讨论】:

      猜你喜欢
      • 2017-10-05
      • 1970-01-01
      • 2013-08-28
      • 2015-12-13
      • 2013-04-20
      • 1970-01-01
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多