Экземпляр на одну и ту же область действия с продолжительностью по умолчанию?
Я хотел бы иметь экземпляр для каждой соответствующей области действия при регистрации в Autofac, но иногда нужно запрашивать экземпляр из глобального контейнера (где нет соответствующей области действия времени жизни). В сценариях, где не существует соответствующей области действия времени жизни, я хочу дать экземпляр верхнего уровня вместо того, чтобы выдавать исключение.
Это возможно?
3 ответа
Я думаю, что вам лучше расширить 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");