Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 删除简单注入器中已注册的装饰器_C#_Dependency Injection_Simple Injector - Fatal编程技术网

C# 删除简单注入器中已注册的装饰器

C# 删除简单注入器中已注册的装饰器,c#,dependency-injection,simple-injector,C#,Dependency Injection,Simple Injector,好吧,我知道这听起来是个奇怪的要求,但这是我的问题。我想为我的WCF服务编写一些集成测试;我有几个关键路径,我想确保它们正常运行。一个测试是确保在关键位置抛出正确的异常,并确保它们在管道中正确传播,而不会在错误的位置被拦截 为此,我使用一个模拟对象覆盖一个现有注册,该对象将在我想要抛出的位置抛出我想要测试的异常。那部分很好用 接下来,我想解析被测系统的命令处理程序,调用handle方法,并断言发生了正确的异常 问题是,当我解析我的命令处理程序时,我实际上得到了一个长链的装饰程序,命令处理程序一直

好吧,我知道这听起来是个奇怪的要求,但这是我的问题。我想为我的WCF服务编写一些集成测试;我有几个关键路径,我想确保它们正常运行。一个测试是确保在关键位置抛出正确的异常,并确保它们在管道中正确传播,而不会在错误的位置被拦截

为此,我使用一个模拟对象覆盖一个现有注册,该对象将在我想要抛出的位置抛出我想要测试的异常。那部分很好用

接下来,我想解析被测系统的命令处理程序,调用handle方法,并断言发生了正确的异常

问题是,当我解析我的命令处理程序时,我实际上得到了一个长链的装饰程序,命令处理程序一直位于底部。在这个链的最顶端有一个装饰器,它是我的全局异常处理程序。我需要注销顶部的这个异常处理装饰程序,因为它阻止我断言抛出了异常。我的容器引导程序非常复杂,所以我绝对不想在我的测试项目中重新创建它的副本,除了这个装饰程序

如果它只是一个标准注册,我可以简单地用一个模拟异常处理程序重写该注册,该处理程序将重新引发异常。不过,据我所知,似乎不可能推翻装饰师的注册。无论如何,我宁愿不走那条路。它通过一个额外的模拟使测试过于复杂。如果我能注销装饰师的注册就更好了

如果不可能注销装饰程序,那么我的下一个最佳解决方案是什么?向我的引导程序添加选项标志以启用/禁用某些注册


谢谢。

据我所知,无法删除任何注册

对于单元测试,您通常根本不会使用容器。由于您要执行集成测试,因此必须使用容器

我可以想出两种方法来做你想做的事

第一个是将一些选项标志传递给引导程序,引导程序在生产环境和测试环境之间进行交换

第二个问题是思考您的测试方法。从您的问题来看,ICommandHandler链中的某个部分似乎应该抛出异常

我认为使用普通的单元测试而不是集成测试来测试是非常简单的。在这种情况下,您不会使用容器,而是手动创建链

commandhandler的单元测试非常简单:

[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void CommandHandlerThrowsCorrectException()
{
    var handler = new Decorator1(new Decorator2(new MyHandler()));

    handler.Handle(new MyCommand);
}
您可以使用其他集成测试来检查传递给WCF服务的命令是否导致生成和处理正确的ICommandHandler链

我通常使用以下测试设置:

使用单元测试测试您手头的所有用例,而不使用容器=>这意味着应用程序中每个组件至少有一个单元测试 使用单元测试来测试每个单独的decorator,而不使用container=>genericeExceptionCommandHandlerDecorator在您的情况下也会处理异常 使用单元测试来测试对容器进行的注册是否正确,以及装饰器是否按照正确的顺序应用,当然是容器的使用。如果使用内置的using container,则此作业的一部分已由容器完成。请验证 使用尽可能少的集成测试,只是测试应用程序是否正常工作和流动。因为每个组件和装饰器都经过单元测试,所以在集成测试中测试应用程序行为的需要要少得多。在某些场景中,您总是希望模拟用户与应用程序的交互,但这种情况应该很少出现,并且主要由单元测试覆盖。
据我所知,不可能取消任何注册

对于单元测试,您通常根本不会使用容器。由于您要执行集成测试,因此必须使用容器

我可以想出两种方法来做你想做的事

第一个是将一些选项标志传递给引导程序,引导程序在生产环境和测试环境之间进行交换

第二个问题是思考您的测试方法。从您的问题来看,ICommandHandler链中的某个部分似乎应该抛出异常

我认为使用普通的单元测试而不是集成测试来测试是非常简单的。在这种情况下,您不会使用容器,而是手动创建链

commandhandler的单元测试非常简单:

[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void CommandHandlerThrowsCorrectException()
{
    var handler = new Decorator1(new Decorator2(new MyHandler()));

    handler.Handle(new MyCommand);
}
您可以使用其他集成测试来检查传递给WCF服务的命令是否导致生成和处理正确的ICommandHandler链

我通常使用以下测试设置:

使用单元测试来测试您手头上的所有案例,无需 ut使用容器=>这意味着应用程序中每个组件至少有一个单元测试 使用单元测试来测试每个单独的decorator,而不使用container=>genericeExceptionCommandHandlerDecorator在您的情况下也会处理异常 使用单元测试来测试对容器进行的注册是否正确,以及装饰器是否按照正确的顺序应用,当然是容器的使用。如果使用内置的using container,则此作业的一部分已由容器完成。请验证 使用尽可能少的集成测试,只是测试应用程序是否正常工作和流动。因为每个组件和装饰器都经过单元测试,所以在集成测试中测试应用程序行为的需要要少得多。在某些场景中,您总是希望模拟用户与应用程序的交互,但这种情况应该很少出现,并且主要由单元测试覆盖。
在简单的注入器中不可能删除注册。可以,但在处理装饰程序时,该方法不起作用。通过向ExpressionBuild事件添加委托,可以在Simple Injector内部添加装饰器。由于注册的委托不存储在任何地方,因此从技术上讲,目前不可能“注销”装饰注册

解决这个问题的方法就是根本不注册那个装饰师。这听起来可能很傻,但这是我一直在使用的一种做法,即使在其他容器中也是如此

例如,您可以将注册的公共部分提取到一个单独的方法中,我们称之为build。此方法缺少与使用它的不同应用程序不同的注册。在您的情况下,您至少有2个“应用程序”;实际应用和集成测试项目。两个项目都可以调用构建,并在调用构建之前或之后添加额外的注册。例如:

var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(InnerMostCommandHandlerDecorator<>));

CompositionRoot.BuildUp(container);

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(OuterMostCommandHandlerDecorator<>));
将配置对象传递给构建方法也是将构建方法与配置系统解耦的一种好方法。这允许您在集成测试期间更轻松地调用building,而不必在测试项目中强制拥有完整配置文件的副本

您还可以在配置对象中拥有装饰器的完整列表,让build方法在其上迭代并注册它们,而不是使用flag属性。这允许调用者在注册装饰器之前从列表中删除或添加装饰器:

var config = new ApplicationConfig();

// Remove decorator
config.CommandHandlerDecorators.Remove(
    typeof(AuthorizationCommandHandlerDecorator<>));

// Add decorator after another decorator
config.CommandHandlerDecorators.Insert(
    index: 1 + config.CommandHandlerDecorators.IndexOf(
        typeof(TransactionCommandHandlerDecorator<>)),
    item: typeof(DeadlockRetryCommandHandlerDecorator<>));

// Add an outer most decorator
config.CommandHandlerDecorators.Add(
    typeof(TestPerformanceProfilingCommandHandlerDecorator<>));

CompositionRoot.BuildUp(container, config);


public static void BuildUp(Container container, ApplicationConfig config) {

    // Lot's of registrations here.

    config.CommandHandlerDecorators.ForEach(type =>
        container.RegisterDecorator(typeof(ICommandHandler<>), type));
}

我在过去非常成功地使用了这三种方法。选择哪个选项取决于您的需要。

在Simple Injector中删除注册是不可能的。可以,但在处理装饰程序时,该方法不起作用。通过向ExpressionBuild事件添加委托,可以在Simple Injector内部添加装饰器。由于注册的委托不存储在任何地方,因此从技术上讲,目前不可能“注销”装饰注册

解决这个问题的方法就是根本不注册那个装饰师。这听起来可能很傻,但这是我一直在使用的一种做法,即使在其他容器中也是如此

例如,您可以将注册的公共部分提取到一个单独的方法中,我们称之为build。此方法缺少与使用它的不同应用程序不同的注册。在您的情况下,您至少有2个“应用程序”;实际应用和集成测试项目。两个项目都可以调用构建,并在调用构建之前或之后添加额外的注册。例如:

var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(InnerMostCommandHandlerDecorator<>));

CompositionRoot.BuildUp(container);

container.RegisterDecorator(typeof(ICommandHandler<>),
    typeof(OuterMostCommandHandlerDecorator<>));
将配置对象传递给构建方法也是将构建方法与配置系统解耦的一种好方法。这允许您在集成测试期间更轻松地调用building,而不必在测试项目中强制拥有完整配置文件的副本

您还可以在配置对象中拥有装饰器的完整列表,让build方法在其上迭代并注册它们,而不是使用flag属性。这允许调用者在注册装饰器之前从列表中删除或添加装饰器:

var config = new ApplicationConfig();

// Remove decorator
config.CommandHandlerDecorators.Remove(
    typeof(AuthorizationCommandHandlerDecorator<>));

// Add decorator after another decorator
config.CommandHandlerDecorators.Insert(
    index: 1 + config.CommandHandlerDecorators.IndexOf(
        typeof(TransactionCommandHandlerDecorator<>)),
    item: typeof(DeadlockRetryCommandHandlerDecorator<>));

// Add an outer most decorator
config.CommandHandlerDecorators.Add(
    typeof(TestPerformanceProfilingCommandHandlerDecorator<>));

CompositionRoot.BuildUp(container, config);


public static void BuildUp(Container container, ApplicationConfig config) {

    // Lot's of registrations here.

    config.CommandHandlerDecorators.ForEach(type =>
        container.RegisterDecorator(typeof(ICommandHandler<>), type));
}
我在过去非常成功地使用了这三种方法。选择哪个选项取决于您的需要