2011-11-04 16 views
6

レジストリ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>(); 
    } 

} 

感謝。

+0

あなたはどのような層について話していますか?異なるプロセスですか?異なるマシン?それらがすべて同じプロセスで実行されている場合は、おそらくビジネスレイヤーがデータレイヤー、具体的にはそのインターフェイスについて少し*知っているものを実行します。あなたが解決しようとしている問題は不明です。あなたのRegistryIOCクラスで何が問題になっていますか? –

+0

サービスレイヤ、BLL、およびDALはすべて別々のプロジェクトです。各プロジェクトはStructureMapを参照します。 サービスレイヤーは他の2つのレイヤーを認識しますが、BLLとDALは互いに知りません。 DAL内からBusiness Objectsを使用している他の開発者を望んでいません。その逆もあります。開発者がBLL内からリポジトリオブジェクトを利用したいと思っていません。サービス層はそれをすべて解決します。 このようにすべてのタイプを登録すると、すべてのレイヤがすべてのレイヤ(プロジェクト)で使用可能になります。 –

+0

さて、Composition Root以外のレイヤーからStructureMapへの参照を追加しないでください。 –

答えて

3

私はこの(および他の)タスクを達成するためにリフレクションを使用しています。それがどのように機能するかを示してみましょう。 、

public interface IConfigurationTask 
{ 
    void Configure(); 
} 

次、このインタフェースを実装する1つ以上のクラスを作成します。

まず最初に行うには、私たちは、初期化タスクを実行するクラスを識別することを可能にするインターフェイスを定義することです。これらのクラスはすべてのプロジェクトに広がっています。これは、「所属する場所」に入れることができるという別の方法です。

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

パズルの最後のピースは、IConfigurationTaskインタフェースを実装するクラスを見つけ、それらのインスタンスを作成し、設定方法を実行することです。これは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を使用して、インスタンスを1ライナー(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の実行をトリガーすることです。たとえば、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プロパティが追加されます)を持つことが有用であることが分かってきましたあなたはそれらを実行します。これは上記のコード例では表示されていませんが、追加するのは簡単です。

希望すると便利です。

+0

この例(素晴らしいです)では、依存関係の連鎖をどのように提案しますか?私がProdRepoに裏打ちされたProdCacheRepoに裏打ちされたIProdRepoのインスタンスを望んでいたら...どうやって連鎖しますか?興味深い! –

+0

@AndrewSiemer私は、あなたが(個々のConfigureメソッドで)それに与える設定に基づいて、IoCフレームワーク(この場合はStructureMap)のタスクであると思います。私が提供したコードは、IoCコンテナ(またはアプリケーションの起動時に初期化する必要があるもの)の「分散コンフィグレーション」のためのメカニズムにすぎません。 –

+0

私はリフレクションライブラリを利用できません。このコードを通常のリフレクションa.CreateInstance( "IConfigurationTask")で試してみると、結果として何も得られません。たぶん私はどこかに何かを見逃しています::-( –

0

複数の独立したContainerインスタンスを作成して設定することができ、ObjectFactoryのstatic-see this articleは使用できません。適切な容器に適切な容器を提供することは、あなたの責任です。

ところで、どのようにレイヤ間通信を処理したいですか?それはどういうわけか難しいでしょうか?私は、レジストリを(おそらくアセンブリを分離するために)分割し、インフラストラクチャレベルでデカップリングを強制するのではなく、「手動で」デカップリングしたままにします。

+0

私の現在の実装を変更する気にはなりません。私の層のそれぞれのクラスにクラス分けされたすべてのレジストリを持つことが最善であれば、私と一緒に涼しいです。私の問題の一部は、適切な容器に適切な層を提供する方法を完全に理解していないということです。私はglobal.asaxローダーに正確に何を入れますか? –

+0

まあ、一般的には、レイヤーごとに異なるエントリーポイントを持たなければならず、それぞれのレイヤーは適切なコンテナを使って独自のファクトリメソッドを持たなければなりません。しかし、私は本当にそのようなグラフ間の相互作用を達成する方法を見ていないので、これは第2段落の質問がある理由です。最後に、下位レベルのコンポーネントYを使用する上位層のコンポーネントXを用意する必要があります.Xが中間層であり、中間層のコンテナによって作成された場合、下位層からの依存性Yもそうです。 – NOtherDev

+0

一般的に答えは、完全に分離されたオブジェクトグラフを持つことは難しいです。だから私はオブジェクトの工場レベルではなくレジストリ/アセンブリレベルでデカップリングを提案したのです。 – NOtherDev

関連する問題