Я использую Autofac 2.5 в asp.net, и у меня возникла проблема, из-за которой компоненты области действия времени жизни решаются как зависимости компонентов одного экземпляра, тем самым разрушая мою безопасность потоков.Это проблема с регистрациями, но я подумал, что 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 генерировать исключение разрешения зависимостей, если это происходит?
ОБНОВЛЕНИЕ Несмотря на то, что это правильное поведение для Autofac - SingleInstance это просто область действия Root - это может быть потенциально опасно в веб-среде.Убедиться в том, что все ваши разработчики получили правильные регистрации, может быть очень сложно.Вот небольшой метод расширения для Autofac, который проверяет поиск экземпляров, чтобы убедиться, что экземпляры с ограниченным сроком действия не могут быть разрешены в корневой области.Я знаю, что это помогло нам устранить проблемы жизненного цикла в нашем веб-проекте.
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();