Структура карты - Как зарегистрировать определенные типы в определенных слоях - PullRequest
6 голосов
/ 04 ноября 2011

Я использую пример реестра DSL для настройки структуры карты. Но благодаря этому все мои зарегистрированные типы доступны на всех уровнях моего приложения, где я добавляю ссылку на карту структуры. Я не хочу, чтобы мой бизнес-уровень знал что-либо о моем уровне доступа к данным и наоборот. Как мне получить Structuremap, чтобы регистрировать только определенные типы для каждого из моих слоев?

Вот код в моем файле global.asax:

ObjectFactory.Initialize(x =>
{
  x.AddRegistry<RegistryIOC>();
});

А вот мой класс RegistryIOC:

public class RegistryIOC : SMRegistry
{

    public RegistryIOC() 
    {
        For<IProfileService>.Use<ProfileService>();
        For<IProctorService>().Use<ProctorService>();

        //Business Logic Objects
        For<IQual>().Use<Qual>();
        For<ITest>().Use<Test>();
        For<IBoldface>().Use<Boldface>();
        For<ITrainingPlan>().Use<TrainingPlan>();
        For<IUnit>().Use<Unit>();

        //Data Transfer Objects
        For<IGenericDTO>().Use<GenericDTO>();
        For<IProfileDTO>().Use<ProfileDTO>();
        For<IQualDTO>().Use<QualDTO>();
        For<IPermissionDTO>().Use<PermissionDTO>();

        //Repository Objects
        For<IProctorRepository>().Use<ProctorRepository>();
        For<IQualsRepository>().Use<QualsRepository>();
        For<ITestRepository>().Use<TestRepository>();
        For<IUnitRepository>().Use<UnitRepository>();
        For<IUserRepository>().Use<UserRepository>();
    }

}

Спасибо за помощь.

Ответы [ 2 ]

3 голосов
/ 04 ноября 2011

Я использую рефлексию для выполнения этой (и других) задач.Позвольте мне показать, как это работает.

Первое, что нужно сделать, - это определить интерфейс, который позволит нам идентифицировать классы, выполняющие задачи инициализации:

public interface IConfigurationTask
{
    void Configure();
}

Затем создайте один или несколько классов.которые реализуют этот интерфейс.Эти классы будут распределены по всем вашим проектам, и это еще один способ сказать, что вы можете поместить их «туда, где они должны».

public class RepositoryInitializer : IConfigurationTask
{
    public void Configure()
    {
        // code that does relevant initialization goes here
    }
}

Последняя часть головоломки - найти классы, которые реализуютИнтерфейс IConfigurationTask, создайте их экземпляр и выполните метод Configure.Это цель ConfigurationTaskRunner:

public static class ConfigurationTaskRunner
{
    public static void Execute( params string[] assemblyNames )
    {
        var assemblies = assemblyNames.Select( Assembly.Load ).Distinct().ToList();
        Execute( assemblies );
    }

    public static void Execute( IEnumerable<Assembly> assemblies )
    {
        var tasks = new List<IConfigurationTask>();
        assemblies.ForEach( a => tasks.AddRange( a.CreateInstances<IConfigurationTask>() ) );

        tasks.ForEach( t => t.Configure() );
    }
}

Код, показанный здесь, использует пользовательское расширение для перебора всех элементов в списке и выполнения действия для каждого элемента (метод ForEach).Я также использую библиотеку отражений , чтобы сделать задачу нахождения и создания экземпляров одной строкой (метод CreateInstances), но вы можете добиться того же, используя простое отражение (как показано в коде ниже)).

public static IList<T> CreateInstances<T>( this Assembly assembly )
{
     var query = from type in assembly.GetTypes().Where( t => typeof(T).IsAssignableFrom( t ) && typeof(T) != t ) 
                 where type.IsClass && ! type.IsAbstract && type.GetConstructor( Type.EmptyTypes ) != null 
                 select (T) Activator.CreateInstance( type );
     return query.ToList();
}    

Последняя часть головоломки - запуск выполнения ConfigurationTaskRunner.Например, в веб-приложении это указывало бы на Application_Start в Global.asax:

// pass in the names of the assemblies we want to scan, hardcoded here as an example 
ConfigurationTaskRunner.Execute( "Foo.dll", "Foo.Domain.dll" );

Я также нашел его полезным с производным IPrioritizedConfigurationTask (который добавляет свойство Priority), чтобы разрешить правильное упорядочениезадачи, прежде чем выполнять их.Это не показано в примере кода выше, но добавить его довольно просто.

Надеюсь, это поможет!

0 голосов
/ 04 ноября 2011

Вы можете создавать и настраивать несколько независимых Container экземпляров и вообще не использовать статический ObjectFactory - см. Эту статью . Тогда вы будете обязаны обеспечивать надлежащие контейнеры для соответствующих слоев.

Кстати, как вы хотите обрабатывать межуровневую связь? Не будет ли это как-то сложно? Я бы лучше разделил реестры (возможно, для разделения сборок) и оставил бы их разъединенными «вручную», вместо того, чтобы навязывать развязку на уровне инфраструктуры.

...