How to register an additional decorator or decorator with optional parameters using structmap asp.net mvc?

I applied the CQRS approach in my application, very dependent on this fantastic article: https://cuttingedge.it/blogs/steven/pivot/entry.php?id=9 . My code for commands and handlers is identical to the article, and this part works well. My problem arises when I try to implement a decorator class to check command validation. Simple command processing interfaces are as follows:

public interface ICommand { } public interface ICommandHandler<TCommand> { void Handle(TCommand command); } 

Then for the check decorator there are:

 public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : CommandBase { private readonly ICommandHandler<TCommand> _decoratedCommandHandler; private readonly ICommandValidator<TCommand> _commandValidator; public ValidationCommandHandlerDecorator(ICommandHandler<TCommand> decoratedCommandHandler, ICommandValidator<TCommand> commandValidator) { _decoratedCommandHandler = decoratedCommandHandler; _commandValidator = commandValidator; } public void Handle(TCommand command) { if (_commandValidator != null) { var validationResult = _commandValidator.Validate(command); if (validationResult != null) { command.Success = false; command.Errors = validationResult; return; } } _decoratedCommandHandler.Handle(command); command.Success = true; } } 

Uses an interface to define validators:

 public interface ICommandValidator<TCommand> { IEnumerable<string> Validate(TCommand command); } 

And CommandBase is a simple base class that allows me to save the success or failure of a command and the errors that occurred if it failed. I prefer this method as an alternative to throwing an exception. All teams inherit this base class.

 public abstract class CommandBase : ICommand { public bool Success { get; set; } public IEnumerable<string> Errors { get; set; } } 

And all this is connected to the IoC container in the structural map registry:

 public class CommandRegistry : Registry { public CommandRegistry() { Scan(s => { s.AssemblyContainingType<CommandBase>(); s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>)); s.ConnectImplementationsToTypesClosing(typeof(ICommandValidator<>)); s.WithDefaultConventions(); For(typeof(ICommandHandler<>)).DecorateAllWith(typeof(ValidationCommandHandlerDecorator<>)); }); } } 

Now, since I register this decorator for each individual ICommandHandler, if I ever have a command that does not need a validator and does not define it, the private field ICommandValidator<TCommand> _commandValidator of the ValidationCommandHandlerDecorator<TCommand> class cannot be found because it , of course, does not exist and will always cause a structural map error:

"No instance is registered by default and cannot be automatically detected for type" ICommandValidator. "No configuration specified for ICommandValidator."

Is there a way in the map structure to determine how to build a ValidationCommandHandlerDecorator so that it uses some type of check by default when it does not exist, without having to either take a dependency on the container in the class, or create an IValidateableCommandHandler<TCommand> interface to process commands using validators?

Thanks.

+4
source share
1 answer

In case someone comes across this later, the solution I came up with was to add the DefaultCommandValidator class to the Null Object pattern class:

 public class DefaultCommandValidator<TCommand> : ICommandValidator<TCommand> where TCommand : CommandBase { public IEnumerable<string> Validate(TCommand command) { return Enumerable.Empty<string>(); } } 

Then add this line to the structural map registry:

 For(typeof(ICommandValidator<>)).Use(typeof(DefaultCommandValidator<>)); 

I did not know that this structure structure syntax would actually use the default instance ONLY if it could not find a specific implementation of ICommandValidator<TCommand> . Now, if I don’t have a validator, I just don’t add it, and the instance of DefaultCommandValidator<TCommand> used to return an empty / successful validation.

+4
source

All Articles