Autofac终身范围装饰器

我正在使用Autofac实现一个命令处理程序模式,并使用它的decorator工具处理交叉切割问题,如日志记录,身份validation等。

我还有依赖项,我只希望作用于请求/响应管道的生命周期。

我在下面有一个示例实现:

public class Program { public static void Main() { var builder = new ContainerBuilder(); builder.RegisterAssemblyModules(typeof(HandlerModule).Assembly); builder.RegisterType().AsSelf() .InstancePerMatchingLifetimeScope("pipline"); var container = builder.Build(); using(var scope = container.BeginLifetimeScope("pipline")) { var pingHandler = scope.Resolve<IHandle>(); pingHandler.Handle(new PingRequest()); } } } public class HandlerModule : Autofac.Module { protected override void Load(ContainerBuilder builder) { builder.RegisterAssemblyTypes(ThisAssembly) .As(type => type.GetInterfaces() .Where(interfaceType => interfaceType.IsClosedTypeOf(typeof (IHandle))) .Select(interfaceType => new KeyedService("IHandle", interfaceType))); builder.RegisterGenericDecorator( typeof(SecondDecoratorHandler), typeof(IHandle), "IHandle" ) .Keyed("SecondDecoratorHandler", typeof(IHandle)); builder.RegisterGenericDecorator( typeof(FirstDecoratorHandler), typeof(IHandle), "SecondDecoratorHandler" ); } } public class LifetimeScopeTester {} public interface IHandle where TRequest : class, IRequest { TResponse Handle(TRequest request); } public interface IRequest { } public class PingRequest : IRequest { } public class PingResponse { } public class PingHandler : IHandle { public PingResponse Handle(PingRequest request) { Console.WriteLine("PingHandler"); return new PingResponse(); } } public class FirstDecoratorHandler : IHandle where TRequest : class, IRequest { private readonly IHandle _decoratedHandler; private readonly LifetimeScopeTester _lifetimeScopeTester; public FirstDecoratorHandler(IHandle decoratedHandler, LifetimeScopeTester lifetimeScopeTester) { _decoratedHandler = decoratedHandler; _lifetimeScopeTester = lifetimeScopeTester; } public TResponse Handle(TRequest request) { Console.WriteLine("FirstDecoratorHandler - LifetimeScopeTester[{0}]", _lifetimeScopeTester.GetHashCode()); return _decoratedHandler.Handle(request); } } public class SecondDecoratorHandler : IHandle where TRequest : class, IRequest { private readonly IHandle _decoratedHandler; private readonly LifetimeScopeTester _lifetimeScopeTester; public SecondDecoratorHandler(IHandle decoratedHandler, LifetimeScopeTester lifetimeScopeTester) { _decoratedHandler = decoratedHandler; _lifetimeScopeTester = lifetimeScopeTester; } public TResponse Handle(TRequest request) { Console.WriteLine("SecondDecoratorHandler - LifetimeScopeTester[{0}]", _lifetimeScopeTester.GetHashCode()); return _decoratedHandler.Handle(request); } } 

正如您所看到的,我将pipleine包装在一个名为pipeline的范围内,这意味着每当我解析LifetimeScopeTesterpipeline范围)时,我都会获得相同的实例。

我认为我可以替换

 using(var scope = container.BeginLifetimeScope("pipline")) { var pingHandler = scope.Resolve<IHandle>(); pingHandler.Handle(new PingRequest()); } 

 var pingHandler = scope.Resolve<IHandle>(); pingHandler.Handle(new PingRequest()); 

通过创建另一个做同样事情的装饰器。

我的第一直觉是:

 public class LifetimeScopeDecoratorHandler : IHandle where TRequest : class, IRequest { private readonly ILifetimeScope _scope; private readonly IHandle _decoratedHandler; public LifetimeScopeDecoratorHandlerAttempt1(ILifetimeScope scope, IHandle decoratedHandler) { _scope = scope; _decoratedHandler = decoratedHandler; } public TResponse Handle(TRequest request) { Console.WriteLine("LifetimeScopeDecoratorHandler"); TResponse response; using (_scope.BeginLifetimeScope("pipeline")) { response = _decoratedHandler.Handle(request); } return response; } } 

但是,如果在注入的时候decoratedHandler汉德勒已经解决了,那将无法解决。

所以我尝试过:

 public class LifetimeScopeHandler : IHandle where TRequest : class, IRequest { private readonly ILifetimeScope _scope; private readonly Func<IHandle> _decoratedHandlerFactory; public LifetimeScopeHandler(ILifetimeScope scope, Func<IHandle> decoratedHandlerFactory) { _scope = scope; _decoratedHandlerFactory = decoratedHandlerFactory; } public TResponse Handle(TRequest request) { Console.WriteLine("LifetimeScopeDecoratorHandler"); TResponse response; using (_scope.BeginLifetimeScope("pipeline")) { var decoratedHandler = _decoratedHandlerFactory(); response = decoratedHandler.Handle(request); } return response; } } 

然而,当调用_decoratedHandlerFactory()尝试再次使用LifetimeScopeHandler装饰器包装内部处理程序时,这无限重复。

是我正在努力实现的目标。

我在https://dotnetfiddle.net/hwujNI上创建了一个dotnetfiddle来演示这个问题。

LifetimeScopeHandler类的Handle方法调用decoratedHandlerFactory委托时,它要求Autofac解析IHandle ,这是一个LifetimeScopeHandler 。 这就是为什么你有一个StackOverflowException 。 我们可以将您的案例简化为此代码示例:

 public class Foo { public Foo(Func fooFactory) { this._fooFactory = fooFactory; } private readonly Func _fooFactory; public void Do() { Foo f = this._fooFactory(); f.Do(); } } 

即使有一个Foo实例,您也会遇到StackOverflowException

为了解决此问题,您必须指明AutofacLifetimeScopeHandlerdecoratedHandlerFactory委托不应该是LifetimeScopeHandler的委托。

您可以使用WithParameter指示使用特定参数的最后一个装饰器:

 builder.RegisterGenericDecorator( typeof(LifetimeScopeHandler<,>), typeof(IHandle<,>), "FirstDecoratorHandler" ) .WithParameter((pi, c) => pi.Name == "decoratedHandlerFactory", (pi, c) => c.ResolveKeyed("FirstDecoratorHandler", pi.ParameterType)) .As(typeof(IHandle<,>)); 

使用此配置,输出将是

LifetimeScopeHandler
FirstDecoratorHandler – LifetimeScopeTester [52243212]
SecondDecoratorHandler – LifetimeScopeTester [52243212]
PingHandler

顺便说一句,你希望LifetimeScopeHandler成为一种特殊的装饰器,它将在特殊范围内创建内部IHandler<,>

您可以通过要求LifetimeScopeHandler为您创建正确的范围并解析之前的Ihandler

 public class LifetimeScopeHandler : IHandle where TRequest : class, IRequest { private readonly ILifetimeScope _scope; public LifetimeScopeHandler(ILifetimeScope scope) { this._scope = scope; } public TResponse Handle(TRequest request) { Console.WriteLine("LifetimeScopeDecoratorHandler"); using (ILifetimeScope s = this._scope.BeginLifetimeScope("pipline")) { var decoratedHandler = s.ResolveKeyed>("FirstDecoratorHandler"); TResponse response = decoratedHandler.Handle(request); return response; } } } 

此实现将要求LifetimeScopeHandler知道链上的第一个装饰器,我们可以通过在其构造函数上发送名称来绕过它。

 public class LifetimeScopeHandler : IHandle where TRequest : class, IRequest { private readonly ILifetimeScope _scope; private readonly String _previousHandlerName; public LifetimeScopeHandler(ILifetimeScope scope, String previousHandlerName) { this._scope = scope; this._previousHandlerName = previousHandlerName; } public TResponse Handle(TRequest request) { Console.WriteLine("LifetimeScopeDecoratorHandler"); using (ILifetimeScope s = this._scope.BeginLifetimeScope("pipline")) { var decoratedHandler = s.ResolveKeyed>(previousHandlerName); TResponse response = decoratedHandler.Handle(request); return response; } } } 

你必须像这样注册:

 builder.RegisterGenericDecorator( typeof(LifetimeScopeHandler<,>), typeof(IHandle<,>), "FirstDecoratorHandler" ) .WithParameter("previousHandlerName", "FirstDecoratorHandler") .As(typeof(IHandle<,>)); 

我们也可以通过不使用RegisterGenericDecorator方法绕过一切。

如果我们像这样注册LifetimeScopeHandler

 builder.RegisterGeneric(typeof(LifetimeScopeHandler<,>)) .WithParameter((pi, c) => pi.Name == "decoratedHandler", (pi, c) => { ILifetimeScope scope = c.Resolve(); ILifetimeScope piplineScope = scope.BeginLifetimeScope("pipline"); var o = piplineScope.ResolveKeyed("FirstDecoratorHandler", pi.ParameterType); scope.Disposer.AddInstanceForDisposal(piplineScope); return o; }) .As(typeof(IHandle<,>)); 

LifetimeScopeHandler现在看起来像所有装饰器:

 public class LifetimeScopeHandler : IHandle where TRequest : class, IRequest { private readonly IHandle _decoratedHandler; public LifetimeScopeHandler(IHandle decoratedHandler) { this._decoratedHandler = decoratedHandler; } public TResponse Handle(TRequest request) { Console.WriteLine("LifetimeScopeDecoratorHandler"); TResponse response = this._decoratedHandler.Handle(request); return response; } } 

顺便说一下,如果在作用域中使用多个IHandler<,> ,并且需要一个pipline作用域,则此解决方案可能会出现问题。 要解决这个问题,你可以看到这个dotnetfiddle: https ://dotnetfiddle.net/rQgy2X但在我看来这很复杂,你可能不需要它。