私は、Autofacで一生涯スコープ登録と一致するインスタンスを持っていますが、場合によってはグローバルなコンテナからインスタンスを要求する必要があります(一致するライフタイムスコープはありません)。ライフタイムスコープが一致しないシナリオでは、例外をスローするのではなく、トップレベルのインスタンスを与えたいと考えています。一致するライフタイムスコープごとのインスタンス、デフォルトでは?
これは可能ですか?
私は、Autofacで一生涯スコープ登録と一致するインスタンスを持っていますが、場合によってはグローバルなコンテナからインスタンスを要求する必要があります(一致するライフタイムスコープはありません)。ライフタイムスコープが一致しないシナリオでは、例外をスローするのではなく、トップレベルのインスタンスを与えたいと考えています。一致するライフタイムスコープごとのインスタンス、デフォルトでは?
これは可能ですか?
私はあなたがより良い新しい生涯オプションを導入することにより、Autofacを拡張したいと思います。私はAutofac源を取り、それらを少し修正:
public static class RegistrationBuilderExtensions
{
public IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerMatchingOrRootLifetimeScope(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();
}
}
コードはちょっと混乱しますが、@Memoizerは正しいです。これを行う唯一の方法は、子スコープの登録をオーバーライドすることです。残念なことに質問には「サポートするシナリオではない1つの生涯スコープスタイルを1つの場所に、別のスタイルを別の場所に配置したい」という質問があります。このようなカスタムコードが必要です。 –
なぜこれが必要ですか?グローバル登録が範囲登録と異なるようにしますか?あるいは、グローバルスコープとタグ付けされたスコープの両方で構成が変わっていない間に、消費者があるケースでインスタンスを1つ、他のインスタンスでインスタンスを取得したいと思っていますか? –
@PavelGatilov後者です。同じ設定、タグ付きスコープごとに異なるインスタンス、グローバルスコープ用に異なるインスタンス。 –