I have an application which modifies records based on commands. I'm using StructureMap as my container and it is not behaving as I would expect.
The application has several commands to update some business entities. I have a number of FluentValidation validators to validate these commands. Some of the commands share the same fields, which I've pulled out into interfaces. I've implemented some validators on those interfaces
//example command
public class MoveCommand
: IMoveAction, IConfigurationAction
{
public string Section { get; set; }
public string Bank { get; set; }
public string Slot { get; set; }
public List<Configuration> Configurations { get; set; }
}
//Interfaces
public interface IConfigurationAction
{
List<Configuration> Configurations { get; set; }
}
public interface IMoveAction
{
string Section { get; set; }
string Bank { get; set; }
string Slot { get; set; }
}
//Validators
public class GameConfigurationValidator
: AbstractValidator<IConfigurationAction>
{
public GameConfigurationValidator()
{
RuleFor(action => action.Configurations).NotEmpty();
}
}
public class MoveActionValidator
: AbstractValidator<IMoveAction>
{
public MoveActionValidator()
{
RuleFor(action => action.Section).NotEmpty();
RuleFor(action => action.Bank).NotEmpty();
RuleFor(action => action.Slot).NotEmpty();
}
}
I'm configuring the StructureMap container like so
var container = new StructureMap.Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.AssemblyContainingType(typeof(Program)); //Everything is in same assembly as Program
scanner.AddAllTypesOf(typeof(IValidator<>));
});
});
When I try to retrieve the validators for MoveCommand, var validators = container.GetAllInstances<IValidator<MoveCommand>>();
, I would expect to get two validators, GameConfigurationValidator and MoveActionValidator, but GetAllInstances is returning only the GameConfigurationValidator. If I define the MoveActionValidator first, it gets returned but not the GameConfigurationValidator.
What do I need to do in order to be able to get all validators for the MoveCommand when using GetAllInstances, i.e. both GameConfigurationValidator and MoveActionValidator?
Full example (requires StructureMap and ServiceStack nuget packages):
using System.Collections.Generic;
using ServiceStack.FluentValidation;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
var container = new StructureMap.Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.AssemblyContainingType(typeof(Program));
scanner.AddAllTypesOf(typeof(IValidator<>));
});
});
var stuff = container.WhatDoIHave();
//IValidator<IConfigurationAction> ServiceStack.FluentValidation Transient ConsoleApplication5.GameConfigurationValidator (Default)
//IValidator<IMoveAction> ServiceStack.FluentValidation Transient ConsoleApplication5.MoveActionValidator (Default)
var validators = container.GetAllInstances<IValidator<MoveCommand>>();
}
}
public class GameConfigurationValidator
: AbstractValidator<IConfigurationAction>
{
public GameConfigurationValidator()
{
RuleFor(action => action.Configurations).NotEmpty();
}
}
public class MoveActionValidator
: AbstractValidator<IMoveAction>
{
public MoveActionValidator()
{
RuleFor(action => action.Section).NotEmpty();
RuleFor(action => action.Bank).NotEmpty();
RuleFor(action => action.Slot).NotEmpty();
}
}
public interface IConfigurationAction
{
List<Configuration> Configurations { get; set; }
}
public interface IMoveAction
{
string Section { get; set; }
string Bank { get; set; }
string Slot { get; set; }
}
public class Configuration
{
public string Theme { get; set; }
public decimal Denomination { get; set; }
public string Par { get; set; }
}
public class MoveCommand
: IMoveAction, IConfigurationAction
{
public string Section { get; set; }
public string Bank { get; set; }
public string Slot { get; set; }
public List<Configuration> Configurations { get; set; }
}
}
you want
scanner.ConnectImplementationsToTypesClosing(typeof (IValidator<>));
instead of
scanner.AddAllTypesOf(typeof(IValidator<>));