私はasp.netでAutofac 2.5を使用していますが、ライフタイムスコープのコンポーネントが単一インスタンスコンポーネントの依存として解決されてスレッドの安全性が損なわれる問題があります。これは登録の問題ですが、私はAutofacがこれを違反とみなし、例外をスローすると考えました。Autofacは混合スコープのコンポーネントを解決します
private class A{}
private class B
{
public B(A a){}
}
[Test]
[ExpectedException()]
public void SingleInstanceCannotResolveLifetimeDependency()
{
var builder = new ContainerBuilder();
builder.RegisterType<A>()
.InstancePerLifetimeScope();
builder.RegisterType<B>()
.SingleInstance();
using (var container = builder.Build())
{
using (var lifetime = container.BeginLifetimeScope())
{
//should throw an exception
//because B is scoped singleton but A is only scoped for the lifetime
var b = lifetime.Resolve<B>();
}
}
}
この場合、Autofacに依存関係解決の例外をスローする方法はありますか?
UPDATE これはAutofacための正しい動作ですが - SingleInstanceはスコープだけルート寿命である - それは、Web環境で潜在的に危険なことができます。すべての開発者が正しい登録を取得していることを確認することは苦しいことがあります。ここでは、ライフタイムスコープのインスタンスがルートスコープで解決されないように、インスタンスルックアップをチェックするAutofacの小さな拡張メソッドがあります。 Webプロジェクトからライフサイクルの問題を取り除くのに役立っていることは分かっています。
public static class NoLifetimeResolutionAtRootScopeExtensions
{
/// <summary>
/// Prevents instances that are lifetime registration from being resolved in the root scope
/// </summary>
public static void NoLifetimeResolutionAtRootScope(this IContainer container)
{
LifetimeScopeBeginning(null, new LifetimeScopeBeginningEventArgs(container));
}
private static void LifetimeScopeBeginning(object sender, LifetimeScopeBeginningEventArgs e)
{
e.LifetimeScope.ResolveOperationBeginning += ResolveOperationBeginning;
e.LifetimeScope.ChildLifetimeScopeBeginning += LifetimeScopeBeginning;
}
private static void ResolveOperationBeginning(object sender, ResolveOperationBeginningEventArgs e)
{
e.ResolveOperation.InstanceLookupBeginning += InstanceLookupBeginning;
}
private static void InstanceLookupBeginning(object sender, InstanceLookupBeginningEventArgs e)
{
var registration = e.InstanceLookup.ComponentRegistration;
var activationScope = e.InstanceLookup.ActivationScope;
if (registration.Ownership != InstanceOwnership.ExternallyOwned
&& registration.Sharing == InstanceSharing.Shared
&& !(registration.Lifetime is RootScopeLifetime)
&& activationScope.Tag.Equals("root"))
{
//would be really nice to be able to get a resolution stack here
throw new DependencyResolutionException(string.Format(
"Cannot resolve a lifetime instance of {0} at the root scope.", registration.Target))
}
}
}
コンテナを作成するときにこれを適用すると、ライフスコープのサービスがルートスコープで解決されたときに例外がスローされます。
container.NoLifetimeResolutionAtRootScope();
おかげで、それは、単一のインスタンスは、単にルート寿命がスコープであることを把握するために私にしばらく時間がかかりました。 – Danielg
小さな拡張メソッドで質問を更新し、これらのケースの例外をスローしました。 "_activationStack"がResolveOperationに公開されているといいですね。もっと有用な情報を投げることができます。 – Danielg