结构图 - 如何在某些图层中注册某些类型

Col*_*ear 6 c# structuremap ioc-container inversion-of-control

我使用Registry DSL示例来配置structuremap.但这样做会使我所有注册类型都可以在我的应用程序的所有层中使用,其中我添加了对结构图的引用.我不希望我的业务层知道有关我的数据访问层的任何信息,反之亦然.如何让structuremap只为每个图层注册特定类型?

这是我的global.asax文件中的代码:

ObjectFactory.Initialize(x =>
{
  x.AddRegistry<RegistryIOC>();
});
Run Code Online (Sandbox Code Playgroud)

这是我的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>();
    }

}
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助.

Mor*_*ner 3

我正在使用反射来完成此(和其他)任务。让我展示一下它是如何工作的。

首先要做的是定义一个接口,使我们能够识别执行初始化任务的类:

public interface IConfigurationTask
{
    void Configure();
}
Run Code Online (Sandbox Code Playgroud)

接下来,创建一个或多个实现该接口的类。这些类将分布在您的所有项目中,这是您可以将它们放在“它们所属的位置”的另一种说法。

public class RepositoryInitializer : IConfigurationTask
{
    public void Configure()
    {
        // code that does relevant initialization goes here
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个难题是找到实现 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() );
    }
}
Run Code Online (Sandbox Code Playgroud)

此处显示的代码使用自定义扩展来迭代列表中的所有项目并为每个项目执行操作(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();
}    
Run Code Online (Sandbox Code Playgroud)

最后一个难题是触发 ConfigurationTaskRunner 的执行。例如,在 Web 应用程序中,这将进入 Global.asax 中的 Application_Start:

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

我还发现它对于派生的 IPrioritizedConfigurationTask(添加 Priority 属性)很有用,可以在执行任务之前对任务进行正确的排序。这没有在上面的示例代码中显示,但添加起来相当简单。

希望这可以帮助!