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

时间:2011-11-04 18:04:47

标签: c# inversion-of-control ioc-container structuremap

我正在使用Registry DSL示例来配置structuremap。但这样做会使我所有注册类型都可以在我的应用程序的所有层中使用,其中我添加了对结构图的引用。我不希望我的业务层知道有关我的数据访问层的任何信息,反之亦然。如何让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 个答案:

答案 0 :(得分:3)

我正在使用反射来完成这个(和其他)任务。让我说明一下它是如何运作的。

要做的第一件事是定义一个接口,允许我们识别执行初始化任务的类:

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方法)。我也使用reflection library来完成定位和实例化实例的任务(CreateInstances方法),但你可以使用普通反射实现相同的功能(如下面的代码所示)。 / p>

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的执行。例如,在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" );

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

希望这有帮助!

答案 1 :(得分:0)

您可以创建和配置多个独立的Container个实例,并且根本不使用静态ObjectFactory - see this article。那么你有责任为适当的层提供合适的容器。

顺便问一下,您希望如何处理层间通信?难道不是很难吗?我宁愿拆分注册表(可能是单独的程序集)并保持“手动”解耦,而不是在基础架构级别强制解耦。