.netstructuremapstructuremap4

StructureMap GetAllInstances returning one instance when several expected


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; }
    }
}

Solution

  • you want

    scanner.ConnectImplementationsToTypesClosing(typeof (IValidator<>));
    

    instead of

    scanner.AddAllTypesOf(typeof(IValidator<>));
    

    see Structure Map: Generic Types