他のコンポーネントで再利用できるクラスライブラリを使用しています。このクラスライブラリでは、依存性注入にUnityを使用しています。このクラスライブラリ用に、テストプロジェクトを作成します。呼び出し元はテストプロジェクトも取得します。私が不確かなことの1つは、バインディングの場所です。これをクラスライブラリに組み込む必要がありますか、それとも呼び出し元のアプリケーションからこれを行う必要がありますか?
4 に答える
答えが選ばれたことは知っていますが、Unityの一部が見落とされていると思います。これは特定のUnityの質問だったので、IUnityContainerExtensionConfiguratorを実装するUnityContainerExtension基本クラスを指摘したいと思いました。これは、APIライブラリを拡張して、コンテナを所有するエントリポイントアプリケーションがライブラリをコンテナに正しく登録することを簡単に確認できるようにするためのものであり、API所有者が登録するものとどうやって。
これは、この目的のためにMicrosoftEnterpriseLibrariesによって使用されます。
ロギングライブラリを単純なものとして使用します。
public class LoggingUnityExtension : UnityContainerExtension
{
protected override void Initialize()
{
Container.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager());
}
}
次に、エントリポイントアプリケーションはこれを行います。
public class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.AddNewExtension<EnterpriseLibraryCoreExtension>();
Container.AddNewExtension<LoggingUnityExtension>();
// ...
}
// ...
}
これで、EnterpriseLibraryとLoggingライブラリのAPIが登録されました。このメソッドを使用するエントリポイントアプリケーションは非常に簡単です。これは、ライブラリ開発者が目標として持つべきものです。
これは興味深い問題です。エントリポイントを持たない再利用可能なアセンブリを依存性注入するにはどうすればよいですか。本当に他の人の答えを見てみたいです。
依存性注入は、エントリポイントアセンブリの責任です。ただし、それぞれがDIを必要とするクラスとアセンブリが多数ある場合は、一部のクラス/アセンブリでそれらが省略され、タスクが面倒になる可能性があります。
ソリューション1
設定より規約を使用します。Foo
クラスの実装などのルールに固執しますIFoo
。多くのDIフレームワークには、規則を使用してそれを設定する手段があります。
解決策2
上記の解決策は、注入のセットアップをパラメーター化する必要がある場合があるため、すべての問題を解決するわけではありません。これが私が問題を解決した方法です(特にMEFによってロードされたアセンブリの場合、これはAutoFac
):
IIocInstaller
コンテナ(またはビルダーが渡される)のインターフェイスを作成しました
public interface IIocInstaller
{
void Setup(ContainerBuilder builder);
}
DIを必要とするアセンブリにフラグを立てるアセンブリ属性を作成しました。
[AttributeUsage(AttributeTargets.Assembly)]
public class ExportAssemblyAttribute : Attribute
{
}
各アセンブリで、DIを設定するクラスを作成します。
[assembly: ExportAssembly]
namespace This.That
{
[Export(typeof(IIocInstaller))]
public class IocInstaller : IIocInstaller
{
public void Setup(ContainerBuilder builder)
{
....
}
}
}
次に、エントリポイントに、アセンブリ属性を持つすべてのロードされたアセンブリ(MEFedアセンブリを含む)を調べ、実装しているタイプを探して、IIocInstaller
それらに対してSetupを呼び出す共通コードがあります。
呼び出し元のアプリケーションからそれを行うと、呼び出し元のアプリケーションにより多くの負担がかかります。初期化を省略してトラブルに巻き込まれる可能性を残します。
クラスライブラリ、たとえば静的コンストラクターでそれを行います。
OKProject.Iocという名前のライブラリを作成します。ここにUnityをインストールします。他のレイヤーをIocライブラリに参照します。そして、Iocライブラリをプレゼンテーション層に。UnityHelperという名前のクラスを作成します。
/// <summary>
/// Bind the given interface in request scope
/// </summary>
public static class IocExtensions
{
public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
}
public static void BindInSingletonScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
}
}
/// <summary>
/// The injection for Unity
/// </summary>
public static class UnityHelper
{
public static IUnityContainer Start()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new Unity.Mvc4.UnityDependencyResolver(container));
return container;
}
/// <summary>
/// Inject
/// </summary>
/// <returns></returns>
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// Database context, one per request, ensure it is disposed
container.BindInRequestScope<IMVCForumContext, MVCForumContext>();
container.BindInRequestScope<IUnitOfWorkManager, UnitOfWorkManager>();
//Bind the various domain model services and repositories that e.g. our controllers require
container.BindInRequestScope<ITopicService, TopicService>();
container.BindInRequestScope<ITopicTagRepository, TopicTagRepository>();
//container.BindInRequestScope<ISessionHelper, SessionHelper>();
return container;
}
}
MvcForumプロジェクトをチェックしてください。MvcForm.Iocクラスライブラリがあります。ライブラリは他のレイヤー参照を取得します。UnityHelperという名前のクラスは1つだけです。
https://github.com/leen3o/mvcforum
これがあなたが探しているワットだといいのですが。