/// <summary> /// Initializes a new instance of the <see cref="ExceptionContext"/> class using the values provided. /// </summary> /// <param name="exceptionInfo">The exception caught.</param> /// <param name="catchBlock">The catch block where the exception was caught.</param> /// <param name="context">The context in which the exception occurred.</param> public ExceptionContext(ExceptionDispatchInfo exceptionInfo, ExceptionContextCatchBlock catchBlock, CommandHandlerContext context) { if (exceptionInfo == null) { throw new ArgumentNullException("exceptionInfo"); } this.ExceptionInfo = exceptionInfo; if (catchBlock == null) { throw new ArgumentNullException("catchBlock"); } this.CatchBlock = catchBlock; if (context == null) { throw new ArgumentNullException("context"); } this.Context = context; CommandHandlerRequest request = context.Request; if (request == null) { throw Error.ArgumentNull(Resources.TypePropertyMustNotBeNull, typeof(HandlerRequest).Name, "Request", "context"); } this.Request = request; }
public ActionInvoker(CommandHandlerContext context, CancellationToken cancellationToken, ServicesContainer services) { Contract.Requires(services != null); this.context = context; this.cancellationToken = cancellationToken; this.services = services; }
/// <summary> /// Invokes a <see cref="ICommandHandler"/>. /// </summary> /// <param name="context">The context of invocation.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A <see cref="Task"/> of HandlerResponse.</returns> public virtual Task<HandlerResponse> InvokeHandlerAsync(CommandHandlerContext context, CancellationToken cancellationToken) { if (context == null) { throw Error.ArgumentNull("context"); } return InvokeActionAsyncCore(context, cancellationToken); }
/// <summary> /// Initializes a new instance of the <see cref="CommandHandlerExecutedContext"/> class. /// </summary> /// <param name="handlerContext">Then handler context.</param> /// <param name="exceptionInfo">The <see cref="ExceptionDispatchInfo"/>. Optionnal.</param> public CommandHandlerExecutedContext(CommandHandlerContext handlerContext, ExceptionDispatchInfo exceptionInfo) { if (handlerContext == null) { throw Error.ArgumentNull("handlerContext"); } this.ExceptionInfo = exceptionInfo; this.handlerContext = handlerContext; }
public HandlerResponse Convert(CommandHandlerContext context, object handlerResult) { if (context == null) { throw Error.ArgumentNull("context"); } Contract.Assert(handlerResult == null); return context.Request.CreateResponse(); }
public CommandHandlerFilterResult(CommandHandlerContext context, ServicesContainer services, ICommandHandlerFilter[] filters) { Contract.Requires(context != null); Contract.Requires(services != null); Contract.Requires(filters != null); this.context = context; this.services = services; this.filters = filters; }
private static async Task<HandlerResponse> InvokeActionAsyncCore(CommandHandlerContext context, CancellationToken cancellationToken) { Contract.Requires(context != null); Contract.Requires(context.Descriptor != null); CommandHandlerDescriptor handlerDescriptor = context.Descriptor; try { object result = await handlerDescriptor.ExecuteAsync(context, cancellationToken); // This is cached in a local for performance reasons. ReturnType is a virtual property on CommandHandlerDescriptor, // or else we'd want to cache this as part of that class. bool isDeclaredTypeHandlerResult = typeof(ICommandHandlerResult).IsAssignableFrom(handlerDescriptor.ReturnType); if (result == null && isDeclaredTypeHandlerResult) { // If the return type of the action descriptor is IHandlerResult, it's not valid to return null throw Error.InvalidOperation(Resources.DefaultHandlerInvoker_NullHandlerResult); } if (isDeclaredTypeHandlerResult || handlerDescriptor.ReturnType == typeof(object)) { ICommandHandlerResult actionResult = result as ICommandHandlerResult; if (actionResult == null && isDeclaredTypeHandlerResult) { // If the return type of the action descriptor is IHandlerResult, it's not valid to return an // object that doesn't implement IHandlerResult throw Error.InvalidOperation(Resources.DefaultHandlerInvoker_InvalidHandlerResult, result.GetType()); } if (actionResult != null) { HandlerResponse response = await actionResult.ExecuteAsync(cancellationToken); if (response == null) { throw Error.InvalidOperation(Resources.DefaultHandlerInvoker_NullHandlerResponse); } HandlerResponse.EnsureResponseHasRequest(response, context.Request); return response; } } // This is a non-IHandlerResult, so run the converter return handlerDescriptor.ResultConverter.Convert(context, result); } catch (HandlerResponseException handlerResponseException) { HandlerResponse response = handlerResponseException.Response; HandlerResponse.EnsureResponseHasRequest(response, context.Request); return response; } }
public virtual Task OnCommandExecutingAsync(CommandHandlerContext handlerContext, CancellationToken cancellationToken) { try { this.OnCommandExecuting(handlerContext); } catch (Exception ex) { return TaskHelpers.FromError(ex); } return TaskHelpers.Completed(); }
public ExceptionFilterResult(CommandHandlerContext context, IExceptionFilter[] filters, IExceptionLogger exceptionLogger, IExceptionHandler exceptionHandler, ICommandHandlerResult innerResult) { Contract.Requires(context != null); Contract.Requires(filters != null); Contract.Requires(exceptionLogger != null); Contract.Requires(exceptionHandler != null); Contract.Requires(innerResult != null); this.context = context; this.filters = filters; this.exceptionLogger = exceptionLogger; this.exceptionHandler = exceptionHandler; this.innerResult = innerResult; }
private static Stack <TransactionScope> GetStack(CommandHandlerContext context) { Contract.Requires(context != null); Contract.Requires(context.Items != null); object value; if (context.Items.TryGetValue(Key, out value)) { return(value as Stack <TransactionScope>); } return(null); }
public void WhenCreatingInstanceThenPropertiesAreDefined() { // Arrange CommandHandlerContext preContext = new CommandHandlerContext(); Exception exception = new Exception(); ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception); // Act CommandHandlerExecutedContext context = new CommandHandlerExecutedContext(preContext, exceptionInfo); // Assert Assert.Null(context.Response); Assert.NotNull(context.ExceptionInfo.SourceException); Assert.Same(context.ExceptionInfo.SourceException, exception); }
public void WhenSettingResultThenResultIsDefined() { // Arrange CommandHandlerContext preContext = new CommandHandlerContext(); Exception exception = new Exception(); ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception); CommandHandlerExecutedContext context = new CommandHandlerExecutedContext(preContext, exceptionInfo); var value = "test"; // Act context.Response = context.Request.CreateResponse("test"); // Assert Assert.Equal(context.Response.Value, value); }
public void WhenCreatingInstanceWithDefaultCtorThenPropertiesAreDefined() { // Arrange // Act CommandHandlerContext context = new CommandHandlerContext(); // Assert Assert.Null(context.Configuration); Assert.Null(context.Request); Assert.Null(context.Command); Assert.Null(context.Descriptor); Assert.Null(context.Request); Assert.NotNull(context.Items); Assert.Equal(0, context.Items.Count); }
public void WhenExecutingFilterThenCacheIsChecked() { // Arrange CacheAttribute filter = this.CreateAttribute(); SimpleCommand command = new SimpleCommand { Property1 = 12, Property2 = "test" }; CommandHandlerRequest request = new CommandHandlerRequest(this.config, command); CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); CommandHandlerContext context = new CommandHandlerContext(request, descriptor); // Act filter.OnCommandExecuting(context); // Assert this.cache.Verify(c => c.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once()); Assert.Null(context.Response); }
/// <summary> /// Converts the result of an handler to an instance of <see cref="HandlerResponse"/>. /// </summary> /// <param name="context">The conversion context.</param> /// <param name="handlerResult">The result to convert.</param> /// <returns>A <see cref="HandlerResponse"/>.</returns> /// <exception cref="InvalidOperationException"></exception> public HandlerResponse Convert(CommandHandlerContext context, object handlerResult) { if (context == null) { throw Error.ArgumentNull("context"); } HandlerResponse response = (HandlerResponse)handlerResult; if (response == null) { throw Error.InvalidOperation(Resources.DefaultHandlerInvoker_NullHandlerResponse); } HandlerResponse.EnsureResponseHasRequest(response, context.Request); return response; }
public void WhenInvokingFilterWithExceptionThenTransactionRollbacks() { // Arrange TransactionFilterAttribute filter = new TransactionFilterAttribute(); CommandHandlerContext executingContext = new CommandHandlerContext(); Exception exception = new Exception(); ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception); CommandHandlerExecutedContext executedContext = new CommandHandlerExecutedContext(executingContext, exceptionInfo); // Act filter.OnCommandExecuting(executingContext); Transaction transaction = Transaction.Current.Clone(); filter.OnCommandExecuted(executedContext); // Assert Assert.Equal(TransactionStatus.Aborted, transaction.TransactionInformation.Status); }
public static Func<Task<HandlerResponse>> InvokeHandlerWithHandlerFiltersAsync(CommandHandlerContext context, CancellationToken cancellationToken, ICommandHandlerFilter[] filters, Func<Task<HandlerResponse>> innerAction) { Contract.Requires(context != null); Contract.Requires(filters != null); Contract.Requires(innerAction != null); Func<Task<HandlerResponse>> result = innerAction; for (int i = filters.Length - 1; i >= 0; i--) { ICommandHandlerFilter filter = filters[i]; Func<Func<Task<HandlerResponse>>, ICommandHandlerFilter, Func<Task<HandlerResponse>>> chainContinuation = (continuation, innerFilter) => () => innerFilter.ExecuteHandlerFilterAsync(context, cancellationToken, continuation); result = chainContinuation(result, filter); } return result; }
public void WhenCreatingInstanceWithParameterCtorThenPropertiesAreDefined() { // Arrange CommandHandlerRequest request = new CommandHandlerRequest(this.config, this.command.Object); CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); // Act CommandHandlerContext context = new CommandHandlerContext(request, descriptor); // Assert Assert.Same(this.config, context.Configuration); Assert.Same(request, context.Request); Assert.Same(request.Command, context.Command); Assert.Same(descriptor, context.Descriptor); Assert.NotNull(context.Request); Assert.NotNull(context.Items); Assert.Equal(0, context.Items.Count); }
public override void OnCommandExecuting(CommandHandlerContext handlerContext) { if (handlerContext == null) { throw Error.ArgumentNull("CommandHandlerContext"); } Stack<TransactionScope> stack = GetStack(handlerContext); if (stack == null) { stack = new Stack<TransactionScope>(); handlerContext.Items[Key] = stack; } TransactionOptions options = new TransactionOptions { Timeout = this.Timeout, IsolationLevel = this.IsolationLevel }; TransactionScope transactionScope = new TransactionScope(this.ScopeOption, options); stack.Push(transactionScope); }
public void WhenInvokingFilterWithoutExceptionThenTransactionCompletes() { // Arrange TransactionFilterAttribute filter = new TransactionFilterAttribute(); HandlerRequest request = new HandlerRequest(this.config, null); CommandHandlerContext executingContext = new CommandHandlerContext(); CommandHandlerExecutedContext executedContext = new CommandHandlerExecutedContext(executingContext, null); executingContext.Response = new HandlerResponse(null); // Act filter.OnCommandExecuting(executingContext); Transaction transaction = Transaction.Current.Clone(); filter.OnCommandExecuted(executedContext); // Assert Assert.Equal(TransactionStatus.Committed, transaction.TransactionInformation.Status); }
public void WhenExecutingFilterToIgnoreThenCacheIsIgnored() { // Arrange CacheAttribute filter = this.CreateAttribute(); SimpleCommand command = new SimpleCommand { Property1 = 12, Property2 = "test" }; SimpleCommand cachedCommand = new SimpleCommand { Property1 = 12, Property2 = "test in cache" }; CommandHandlerRequest request = new CommandHandlerRequest(this.config, command); CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(NotCachedCommand), typeof(NotCachedCommandHandler)); CommandHandlerContext context = new CommandHandlerContext(request, descriptor); this.cache.Setup(c => c.Get(It.IsAny<string>(), It.IsAny<string>())).Returns(new CacheAttribute.CacheEntry(cachedCommand)); // Act filter.OnCommandExecuting(context); // Assert this.cache.Verify(c => c.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Never()); Assert.Null(context.Response); }
public void WhenExecuteExceptionFilterAsyncThenReturnsCompletedTask() { // Arrange Mock<MessageProcessorTests.ISpy> spy = new Mock<MessageProcessorTests.ISpy>(); IExceptionFilter filter = new CustomExceptionFilterAttribute(spy.Object); CommandHandlerContext handlerContext = new CommandHandlerContext(); Exception exception = new Exception(); ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception); CommandHandlerExecutedContext handlerExecutedContext = new CommandHandlerExecutedContext(handlerContext, exceptionInfo); CancellationToken cancellationToken = new CancellationToken(); // Act var task = filter.ExecuteExceptionFilterAsync(handlerExecutedContext, cancellationToken); // Assert Assert.NotNull(task); Assert.True(task.IsCompleted); spy.Verify(s => s.Spy("OnException"), Times.Once()); }
/// <summary> /// Execute the request via the worker. /// </summary> /// <param name="request">The <see cref="HandlerRequest"/> to execute.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> to cancel the execution.</param> /// <returns>The result of the command, if any.</returns> public Task<HandlerResponse> ExecuteAsync(CommandHandlerRequest request, CancellationToken cancellationToken) { if (request == null) { throw Error.ArgumentNull("request"); } cancellationToken.ThrowIfCancellationRequested(); ServicesContainer servicesContainer = request.Configuration.Services; ICommandHandlerSelector handlerSelector = servicesContainer.GetHandlerSelector(); CommandHandlerDescriptor descriptor = handlerSelector.SelectHandler(request); ICommandHandler commandHandler = descriptor.CreateHandler(request); if (commandHandler == null) { throw CreateHandlerNotFoundException(descriptor); } request.RegisterForDispose(commandHandler, true); CommandHandlerContext context = new CommandHandlerContext(request, descriptor); context.Handler = commandHandler; commandHandler.CommandContext = context; CommandFilterGrouping commandFilterGrouping = descriptor.GetFilterGrouping(); ICommandHandlerResult result = new CommandHandlerFilterResult(context, servicesContainer, commandFilterGrouping.CommandHandlerFilters); if (descriptor.RetryPolicy != RetryPolicy.NoRetry) { result = new RetryHandlerResult(descriptor.RetryPolicy, result); } if (commandFilterGrouping.ExceptionFilters.Length > 0) { IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(servicesContainer); IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(servicesContainer); result = new ExceptionFilterResult(context, commandFilterGrouping.ExceptionFilters, exceptionLogger, exceptionHandler, result); } return result.ExecuteAsync(cancellationToken); }
/// <summary> /// Occurs before the handle method is invoked. /// </summary> /// <param name="handlerContext">The handler context.</param> public override void OnCommandExecuting(CommandHandlerContext handlerContext) { if (handlerContext == null) { throw new ArgumentNullException("handlerContext"); } Stack<IDisposable> stack = GetStack(handlerContext); if (stack == null) { stack = new Stack<IDisposable>(); handlerContext.Items[Key] = stack; } MiniProfiler profiler = MiniProfiler.Current; if (profiler != null) { IDisposable step = profiler.Step(handlerContext.Descriptor.Name); stack.Push(step); } }
public override void OnCommandExecuting(CommandHandlerContext handlerContext) { if (handlerContext == null) { throw Error.ArgumentNull("CommandHandlerContext"); } Stack <TransactionScope> stack = GetStack(handlerContext); if (stack == null) { stack = new Stack <TransactionScope>(); handlerContext.Items[Key] = stack; } TransactionOptions options = new TransactionOptions { Timeout = this.Timeout, IsolationLevel = this.IsolationLevel }; TransactionScope transactionScope = new TransactionScope(this.ScopeOption, options); stack.Push(transactionScope); }
public void WhenExecutedFilterWithKeyThenCacheIsUpdated() { // Arrange CacheAttribute filter = this.CreateAttribute(); SimpleCommand command = new SimpleCommand { Property1 = 12, Property2 = "test" }; CommandHandlerRequest request = new CommandHandlerRequest(this.config, command); CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); CommandHandlerContext context = new CommandHandlerContext(request, descriptor); filter.OnCommandExecuting(context); CommandHandlerExecutedContext executedContext = new CommandHandlerExecutedContext(context, null); // Act filter.OnCommandExecuted(executedContext); // Assert this.cache.Verify(c => c.Add(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<DateTimeOffset>(), It.IsAny<string>()), Times.Once()); }
// Generate a unique ID of normalized key names + key values private string GetUniqueIdFromCommand(CommandHandlerContext filterContext) { Contract.Requires(filterContext != null); Contract.Requires(filterContext.Configuration != null); Contract.Requires(filterContext.Command != null); IModelFlattener flattener = filterContext.Configuration.Services.GetModelFlattener(); ModelMetadataProvider metadataProvider = filterContext.Configuration.Services.GetModelMetadataProvider(); ModelDictionary parameters = flattener.Flatten(filterContext.Command, filterContext.Command.GetType(), metadataProvider, string.Empty); IEnumerable<string> keys = SplitVaryByParam(this.VaryByParams); keys = (keys ?? parameters.Keys).OrderBy(key => key, StringComparer.Ordinal); return CreateUniqueId(keys.Concat(keys.Select(key => parameters.ContainsKey(key) ? parameters[key] : null))); }
private string GetUniqueId(CommandHandlerContext filterContext) { Contract.Requires(filterContext != null); Contract.Requires(filterContext.Descriptor != null); StringBuilder uniqueIdBuilder = new StringBuilder(); // Unique ID of the handler description AppendPartToUniqueIdBuilder(uniqueIdBuilder, filterContext.Descriptor.HandlerType); if (this.VaryByUser && filterContext.User != null) { AppendPartToUniqueIdBuilder(uniqueIdBuilder, filterContext.User.Identity.Name); } // Unique ID from the VaryByParams settings, if any uniqueIdBuilder.Append(this.GetUniqueIdFromCommand(filterContext)); // The key is typically too long to be useful, so we use a cryptographic hash // as the actual key (better randomization and key distribution, so small vary // values will generate dramtically different keys). using (SHA256 sha = SHA256.Create()) { return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(uniqueIdBuilder.ToString()))); } }
/// <summary> /// Occurs before the handle method is invoked. /// </summary> /// <param name="handlerContext">The handler context.</param> public override void OnCommandExecuting(CommandHandlerContext handlerContext) { if (handlerContext == null) { throw Error.ArgumentNull("CommandHandlerContext"); } if (ShouldIgnoreCache(handlerContext.Descriptor)) { return; } string key = this.GetUniqueId(handlerContext); CacheEntry entry = this.cache.Get(key) as CacheEntry; if (entry != null) { handlerContext.Response = new HandlerResponse(handlerContext.Request, entry.Value); return; } handlerContext.Items[CacheKey] = key; }
public void WhenExecutedFilterVaryByParamsSetIncorrectlyThenCacheIsAlwaysUsed() { // Arrange CacheAttribute filter = this.CreateAttribute(new MemoryCache("test")); filter.Duration = 10; filter.VaryByParams = "XXXX"; CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); SimpleCommand command1 = new SimpleCommand { Property1 = 1, Property2 = "test1" }; CommandHandlerRequest request1 = new CommandHandlerRequest(this.config, command1); CommandHandlerContext context1 = new CommandHandlerContext(request1, descriptor); CommandHandlerExecutedContext executedContext1 = new CommandHandlerExecutedContext(context1, null); executedContext1.SetResponse("result1"); SimpleCommand command2 = new SimpleCommand { Property1 = 2, Property2 = "test2" }; CommandHandlerRequest request2 = new CommandHandlerRequest(this.config, command2); CommandHandlerContext context2 = new CommandHandlerContext(request2, descriptor); CommandHandlerExecutedContext executedContext2 = new CommandHandlerExecutedContext(context2, null); executedContext2.SetResponse( "result2"); SimpleCommand command3 = new SimpleCommand { Property1 = 2, Property2 = "test3" }; CommandHandlerRequest request3 = new CommandHandlerRequest(this.config, command3); CommandHandlerContext context3 = new CommandHandlerContext(request3, descriptor); CommandHandlerExecutedContext executedContext3 = new CommandHandlerExecutedContext(context3, null); executedContext3.SetResponse("result3"); // Act filter.OnCommandExecuting(context1); filter.OnCommandExecuted(executedContext1); filter.OnCommandExecuting(context2); filter.OnCommandExecuted(executedContext2); filter.OnCommandExecuting(context3); filter.OnCommandExecuted(executedContext3); // Assert Assert.Equal("result1", executedContext1.Response.Value); Assert.Equal("result1", executedContext2.Response.Value); Assert.Equal("result1", executedContext3.Response.Value); }
public void WhenExecutedFilterWithExceptionThenCacheIsNotUpdated() { // Arrange CacheAttribute filter = this.CreateAttribute(); SimpleCommand command = new SimpleCommand { Property1 = 12, Property2 = "test" }; CommandHandlerRequest request = new CommandHandlerRequest(this.config, command); CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); CommandHandlerContext context = new CommandHandlerContext(request, descriptor); Exception exception = new Exception(); ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(exception); CommandHandlerExecutedContext executedContext = new CommandHandlerExecutedContext(context, exceptionInfo); // Act filter.OnCommandExecuted(executedContext); // Assert this.cache.Verify(c => c.Add(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<DateTimeOffset>(), It.IsAny<string>()), Times.Never()); Assert.Null(context.Response); }
public void WhenExecutedFilterVaryByUserThenCacheIsUpdated() { // Arrange CacheAttribute filter = this.CreateAttribute(new MemoryCache("test")); filter.Duration = 10; filter.VaryByUser = true; filter.VaryByParams = CacheAttribute.VaryByParamsNone; CommandHandlerDescriptor descriptor = new CommandHandlerDescriptor(this.config, typeof(SimpleCommand), typeof(SimpleCommandHandler)); SimpleCommand command1 = new SimpleCommand { Property1 = 1, Property2 = "test1" }; CommandHandlerRequest request1 = new CommandHandlerRequest(this.config, command1); CommandHandlerContext context1 = new CommandHandlerContext(request1, descriptor); context1.User = new GenericPrincipal(new GenericIdentity("user1"), null); CommandHandlerExecutedContext executedContext1 = new CommandHandlerExecutedContext(context1, null); executedContext1.Response = new HandlerResponse(request1, "result1"); SimpleCommand command2 = new SimpleCommand { Property1 = 1, Property2 = "test1" }; CommandHandlerRequest request2 = new CommandHandlerRequest(this.config, command2); CommandHandlerContext context2 = new CommandHandlerContext(request2, descriptor); context2.User = new GenericPrincipal(new GenericIdentity("user2"), null); CommandHandlerExecutedContext executedContext2 = new CommandHandlerExecutedContext(context2, null); executedContext2.Response = new HandlerResponse(request2, "result2"); SimpleCommand command3 = new SimpleCommand { Property1 = 1, Property2 = "test1" }; CommandHandlerRequest request3 = new CommandHandlerRequest(this.config, command3); CommandHandlerContext context3 = new CommandHandlerContext(request3, descriptor); context3.User = new GenericPrincipal(new GenericIdentity("user1"), null); CommandHandlerExecutedContext executedContext3 = new CommandHandlerExecutedContext(context3, null); executedContext3.Response = new HandlerResponse(request3, "result3"); // Act filter.OnCommandExecuting(context1); filter.OnCommandExecuted(executedContext1); filter.OnCommandExecuting(context2); filter.OnCommandExecuted(executedContext2); filter.OnCommandExecuting(context3); filter.OnCommandExecuted(executedContext3); // Assert Assert.Equal("result1", executedContext1.Response.Value); Assert.Equal("result2", executedContext2.Response.Value); Assert.Equal("result1", executedContext3.Response.Value); }