Voici ma solution et mes projets:
- Librairie (solution)
- BookStore.Coupler (projet)
- Bootstrapper.cs
- BookStore.Domain (projet)
- CreateBookCommandValidator.cs
- CompositeValidator.cs
- IValidate.cs
- IValidator.cs
- ICommandHandler.cs
- BookStore.Infrastructure (projet)
- CreateBookCommandHandler.cs
- ValidationCommandHandlerDecorator.cs
- BookStore.Web (projet)
- Global.asax
- BookStore.BatchProcesses (projet)
- Program.cs
- BookStore.Coupler (projet)
Bootstrapper.cs :
public static class Bootstrapper.cs
{
// I'm using SimpleInjector as my DI Container
public static void Initialize(Container container)
{
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>), typeof(CreateBookCommandHandler).Assembly);
container.RegisterDecorator(typeof(ICommandHandler<>), typeof(ValidationCommandHandlerDecorator<>));
container.RegisterManyForOpenGeneric(typeof(IValidate<>),
AccessibilityOption.PublicTypesOnly,
(serviceType, implTypes) => container.RegisterAll(serviceType, implTypes),
typeof(IValidate<>).Assembly);
container.RegisterSingleOpenGeneric(typeof(IValidator<>), typeof(CompositeValidator<>));
}
}
CreateBookCommandValidator.cs
public class CreateBookCommandValidator : IValidate<CreateBookCommand>
{
public IEnumerable<IValidationResult> Validate(CreateBookCommand book)
{
if (book.Author == "Evan")
{
yield return new ValidationResult<CreateBookCommand>("Evan cannot be the Author!", p => p.Author);
}
if (book.Price < 0)
{
yield return new ValidationResult<CreateBookCommand>("The price can not be less than zero", p => p.Price);
}
}
}
CompositeValidator.cs
public class CompositeValidator<T> : IValidator<T>
{
private readonly IEnumerable<IValidate<T>> validators;
public CompositeValidator(IEnumerable<IValidate<T>> validators)
{
this.validators = validators;
}
public IEnumerable<IValidationResult> Validate(T instance)
{
var allResults = new List<IValidationResult>();
foreach (var validator in this.validators)
{
var results = validator.Validate(instance);
allResults.AddRange(results);
}
return allResults;
}
}
IValidate.cs
public interface IValidate<T>
{
IEnumerable<IValidationResult> Validate(T instance);
}
IValidator.cs
public interface IValidator<T>
{
IEnumerable<IValidationResult> Validate(T instance);
}
ICommandHandler.cs
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
CreateBookCommandHandler.cs
public class CreateBookCommandHandler : ICommandHandler<CreateBookCommand>
{
private readonly IBookStore _bookStore;
public CreateBookCommandHandler(IBookStore bookStore)
{
_bookStore = bookStore;
}
public void Handle(CreateBookCommand command)
{
var book = new Book { Author = command.Author, Name = command.Name, Price = command.Price };
_bookStore.SaveBook(book);
}
}
ValidationCommandHandlerDecorator.cs
public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decorated;
private readonly IValidator<TCommand> validator;
public ValidationCommandHandlerDecorator(ICommandHandler<TCommand> decorated, IValidator<TCommand> validator)
{
this.decorated = decorated;
this.validator = validator;
}
public void Handle(TCommand command)
{
var results = validator.Validate(command);
if (!results.IsValid())
{
throw new ValidationException(results);
}
decorated.Handle(command);
}
}
Global.asax
// inside App_Start()
var container = new Container();
Bootstrapper.Initialize(container);
// more MVC specific bootstrapping to the container. Like wiring up controllers, filters, etc..
Program.cs
// Pretty much the same as the Global.asax
Désolé pour la longue configuration du problème, je n'ai pas de meilleur moyen d'expliquer cela que de détailler mon problème réel.
Je ne veux pas créer mon CreateBookCommandValidator public
. Je préférerais que ce soit, internal
mais si je le fais, internal
je ne pourrai pas l'enregistrer avec mon conteneur DI. La raison pour laquelle je voudrais que ce soit interne est parce que le seul projet qui devrait avoir la notion de mes implémentations IValidate <> est dans le projet BookStore.Domain. Tout autre projet doit simplement consommer IValidator <> et le CompositeValidator doit être résolu, ce qui remplira toutes les validations.
Comment puis-je utiliser l'injection de dépendance sans interrompre l'encapsulation? Ou est-ce que je me trompe?