Autofacで一致するライフタイムスコープの登録ごとにインスタンスを作成したいのですが、グローバルコンテナ(一致するライフタイムスコープがない場合)からインスタンスをリクエストする必要がある場合があります。一致するライフタイムスコープが存在しないシナリオでは、例外をスローするのではなく、トップレベルのインスタンスを提供したいと思います。
これは可能ですか?
Autofacで一致するライフタイムスコープの登録ごとにインスタンスを作成したいのですが、グローバルコンテナ(一致するライフタイムスコープがない場合)からインスタンスをリクエストする必要がある場合があります。一致するライフタイムスコープが存在しないシナリオでは、例外をスローするのではなく、トップレベルのインスタンスを提供したいと思います。
これは可能ですか?
新しいライフタイムオプションを導入して、Autofacを拡張したほうがいいと思います。Autofacソースを取得し、少し変更しました。
public static class RegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerMatchingOrRootLifetimeScope<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, params object[] lifetimeScopeTag)
{
if (lifetimeScopeTag == null) throw new ArgumentNullException("lifetimeScopeTag");
builder.RegistrationData.Sharing = InstanceSharing.Shared;
builder.RegistrationData.Lifetime = new MatchingScopeOrRootLifetime(lifetimeScopeTag);
return builder;
}
}
public class MatchingScopeOrRootLifetime: IComponentLifetime
{
readonly object[] _tagsToMatch;
public MatchingScopeOrRootLifetime(params object[] lifetimeScopeTagsToMatch)
{
if (lifetimeScopeTagsToMatch == null) throw new ArgumentNullException("lifetimeScopeTagsToMatch");
_tagsToMatch = lifetimeScopeTagsToMatch;
}
public ISharingLifetimeScope FindScope(ISharingLifetimeScope mostNestedVisibleScope)
{
if (mostNestedVisibleScope == null) throw new ArgumentNullException("mostNestedVisibleScope");
var next = mostNestedVisibleScope;
while (next != null)
{
if (_tagsToMatch.Contains(next.Tag))
return next;
next = next.ParentLifetimeScope;
}
return mostNestedVisibleScope.RootLifetimeScope;
}
}
これらのクラスをプロジェクトに追加し、コンポーネントを次のように登録するだけです。
builder.RegisterType<A>.InstancePerMatchingOrRootLifetimeScope("TAG");
自分で試したことはありませんが、うまくいくはずです。
考えられる解決策は、子の有効期間スコープで登録をオーバーライドすることです。
サンプル:
public enum Scopes
{
TestScope
}
public class Test
{
public string Description { get; set; }
}
public class Tester
{
public void DoTest()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Test>()
.OnActivating(args => args.Instance.Description = "FromRoot")
.SingleInstance();
var container = builder.Build();
var scope = container.BeginLifetimeScope(Scopes.TestScope, b => b
.RegisterType<Test>()
.InstancePerMatchingLifetimeScope(Scopes.TestScope)
.OnActivating(args => args.Instance.Description = "FromScope"));
var test1 = container.Resolve<Test>();
Console.WriteLine(test1.Description); //writes FromRoot
var test2 = scope.Resolve<Test>();
Console.WriteLine(test2.Description); //writes FromScope
Console.ReadLine();
}
}
ルート コンテナー自体は、タグ名: のライフタイム スコープでありroot
、で定義されています。LifetimeScope.RootTag
したがって、次のことができます。
using Autofac.Core.Lifetime;
builder.RegisterType<Service>().As<IService>()
.InstancePerMatchingLifetimeScope(LifetimeScope.RootTag, "foobar");