C# Autofac EasyNetQ:工作单元

C# Autofac EasyNetQ:工作单元,c#,autofac,unit-of-work,easynetq,C#,Autofac,Unit Of Work,Easynetq,Autofac和EasyNetQ几乎一直都很容易使用,但今天我们面临着一种挑战:我想为用户设置工作单元 class Program { static void Main(string[] args) { var container = AutofacContainerFactory.Build(); using (var scope = container.BeginLifetimeScope())

Autofac和EasyNetQ几乎一直都很容易使用,但今天我们面临着一种挑战:我想为用户设置工作单元

class Program
    {
        static void Main(string[] args)
        {
            var container = AutofacContainerFactory.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                var bus = scope.Resolve<IBus>();

                bus.Subscribe<SomeMessage>("some.queue", container.Resolve<ISomeMessageHandler>().Handle);

                Console.WriteLine("Listening for messages. Hit <return> to quit.");
                Console.ReadLine();
            }

        }
    }
类程序
{
静态void Main(字符串[]参数)
{
var container=AutofacContainerFactory.Build();
使用(var scope=container.BeginLifetimeScope())
{
var bus=scope.Resolve();
订阅(“some.queue”,container.Resolve().Handle);
Console.WriteLine(“监听消息。点击退出”);
Console.ReadLine();
}
}
}

这在控制台应用程序中非常简单,但如何正确设置UoW:如果在调用handler Handle方法之前调用某个拦截器,并且在执行之后调用UoW,我会很高兴。我能想到的另一个解决方案是在Handle方法中执行所有操作:可能使用某种UnitOfWork装饰器模式。我在等你的想法。

我已经创建了一个AutofacMessageDispatcher,可以完成所有这些:

public class AutofacMessageDispatcher : IAutoSubscriberMessageDispatcher
{
    readonly ILifetimeScope _component;
    readonly IMessageContextFactory _contextFactory;
    public const string PerMessageLifeTimeScopeTag = "AutofacMessageScope";
    public const string GlobalPipeTag = "global";

    public AutofacMessageDispatcher(ILifetimeScope component, IMessageContextFactory contextFactory)
    {
        _component = component;
        _contextFactory = contextFactory;
    }

    static IEnumerable<IErrorHandler> GetErrorHandlers<TConsumer>(TConsumer consumer, IComponentContext scope)
    {
        var errorHandlers = consumer.GetType()
            .GetTypeInfo().GetAttributes<ErrorHandlerAttribute>()
            .OrderBy(attribute => attribute.Order)
            .Select(attribute => attribute.Initialize((IErrorHandler) scope.Resolve(attribute.ErrorHandlerType)))
            .Union(scope.ResolveNamed<IEnumerable<IErrorHandler>>(GlobalPipeTag), a => a.GetType()); // perform the distinction in the union on GetType so we only get 1 handler of the same type

        if (consumer is IErrorHandler consumerAsErrorHandler)
            errorHandlers = errorHandlers.Concat(new[] { consumerAsErrorHandler });

        return errorHandlers;
    }

    static IEnumerable<IPipe> GetPipeLine<TConsumer>(TConsumer consumer, IComponentContext scope)
    {
        var pipeLine = consumer.GetType()
            .GetTypeInfo().GetAttributes<PipeAttribute>()
            .OrderBy(attribute => attribute.Order)
            .Select(attribute => attribute.Initialize((IPipe) scope.Resolve(attribute.PipeType)))
            .Union(scope.ResolveNamed<IEnumerable<IPipe>>(GlobalPipeTag), a => a.GetType()); // perform the distinction in the union on GetType so we only get 1 handler of the same type

        return pipeLine;
    }

    [HandleProcessCorruptedStateExceptions]
    public void Dispatch<TMessage, TConsumer>(TMessage message)
        where TMessage : class
        where TConsumer : IConsume<TMessage>
    {
        using (var scope = _component.BeginLifetimeScope(PerMessageLifeTimeScopeTag, _contextFactory.RegisterMessageContext(typeof(TConsumer), message)))
        {
            var consumer = scope.Resolve<TConsumer>();
            var pipeLine = GetPipeLine(consumer, scope).ToArray();
            pipeLine.Each(p => p.OnBeforeConsume(consumer, message));

            Exception exception = null;
            try
            {
                consumer.Consume(message);
            }
            catch (Exception e) when (GetErrorHandlers(consumer, scope).Any(p => p.OnError(consumer, message, e)))
            {
                exception = e;
            }
            pipeLine.Reverse().Each(p => p.OnAfterConsume(consumer, message, exception));
        }
    }

    [HandleProcessCorruptedStateExceptions]
    public async Task DispatchAsync<TMessage, TConsumer>(TMessage message)
        where TMessage : class
        where TConsumer : IConsumeAsync<TMessage>
    {
        using (var scope = _component.BeginLifetimeScope(PerMessageLifeTimeScopeTag, _contextFactory.RegisterMessageContext(typeof(TConsumer), message)))
        {
            var consumer = scope.Resolve<TConsumer>();
            var pipes = GetPipeLine(consumer, scope).ToArray();

            Exception exception = null;

            foreach (var hook in pipes)
                await hook.OnBeforeConsumeAsync(consumer, message);
            try
            {
                await consumer.Consume(message);
            }
            catch (Exception e) when (GetErrorHandlers(consumer, scope).Any(p => p.OnErrorAsync(consumer, message, e)))
            {
                exception = e;
            }
            foreach (var hook in pipes.Reverse())
                await hook.OnAfterConsumeAsync(consumer, message, exception);
        }
    }
}        

public interface IMessageContextFactory
{
    Action<ContainerBuilder> RegisterMessageContext<TMessage>(Type consumerType, TMessage message) where TMessage : class;
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ErrorHandlerAttribute : Attribute  
{
    public ErrorHandlerAttribute(Type errorHandlerType, int order = 0)
    {
        ErrorHandlerType = errorHandlerType;
        Order = order;
    }

    public Type ErrorHandlerType { get; set; }
    public int Order { get; set; }

    public virtual IErrorHandler Initialize(IErrorHandler handler)
    {
        return handler;
    }
}

public interface IErrorHandler
{
    bool OnError<TMessage, TConsumer>(TConsumer consumer, TMessage message, Exception exception)
        where TMessage : class
        where TConsumer : IConsume<TMessage>;

    bool OnErrorAsync<TMessage, TConsumer>(TConsumer consumer, TMessage message, Exception exception)
        where TMessage : class
        where TConsumer : IConsumeAsync<TMessage>;
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class PipeAttribute : Attribute  
{
    public PipeAttribute(Type pipeType, int order = 0)
    {
        PipeType = pipeType;
        Order = order;
    }

    public Type PipeType { get; set; }
    public int Order { get; set; }

    public IPipe Initialize(IPipe pipe)
    {
        return pipe;
    }
}

public interface IPipe
{
    void OnBeforeConsume<TMessage, TConsumer>(TConsumer consumer, TMessage message)
        where TMessage : class
        where TConsumer : IConsume<TMessage>;

    void OnAfterConsume<TMessage, TConsumer>(TConsumer consumer, TMessage message, [CanBeNull] Exception exception)
        where TMessage : class
        where TConsumer : IConsume<TMessage>;

    Task OnBeforeConsumeAsync<TMessage, TConsumer>(TConsumer consumer, TMessage message)
        where TMessage : class
        where TConsumer : IConsumeAsync<TMessage>;

    Task OnAfterConsumeAsync<TMessage, TConsumer>(TConsumer consumer, TMessage message, [CanBeNull] Exception exception)
        where TMessage : class
        where TConsumer : IConsumeAsync<TMessage>;
}

public interface IMessageContext
{
        object Message { get; }
}
public class MessageContext : IMessageContext
{
    public MessageContext(object message)
    {
        Message = message;
    }

    public object Message { get; set; }
}

public class MessageContextFactory : IMessageContextFactory
{
    readonly ILogger _logger;

    public MessageContextFactory()
    {
        _logger = logger;
    }

    public Action<ContainerBuilder> RegisterMessageContext<TMessage>(Type consumerType, TMessage message) where TMessage : class
    {
        return builder =>
        {
            builder.RegisterInstance(new MessageContext(message)).As<IMessageContext>().AsSelf();
            var forContext = _logger.ForContext(message.GetType());
            builder.RegisterInstance(forContext).As<ILogger>().AsSelf();
        };
    }
}


public interface IMessageContextFactory
{
    Action<ContainerBuilder> RegisterMessageContext<TMessage>(Type consumerType, TMessage message) where TMessage : class;
}
公共类AutofacMessageDispatcher:IAutoSubscriberMessageDispatcher
{
只读ILifetimeScope\u组件;
只读IMessageContextFactory\u contextFactory;
public const string PerMessageLifeTimeScopeTag=“AutofacMessageScope”;
public const string GlobalPipeTag=“global”;
公共AutofacMessageDispatcher(ILifetimeScope组件,IMessageContextFactory contextFactory)
{
_组件=组件;
_contextFactory=contextFactory;
}
静态IEnumerable GetErrorHandlers(TConsumer使用者,IComponentContext作用域)
{
var errorHandlers=consumer.GetType()
.GetTypeInfo().GetAttributes()
.OrderBy(attribute=>attribute.Order)
.Select(attribute=>attribute.Initialize((IErrorHandler)scope.Resolve(attribute.ErrorHandlerType)))
.Union(scope.ResolveNamed(GlobalPipeTag),a=>a.GetType());//在联合中对GetType执行区分,这样我们只会得到1个相同类型的处理程序
if(使用者是IErrorHandler consumerAsErrorHandler)
errorHandlers=errorHandlers.Concat(新[]{consumerAsErrorHandler});
返回错误处理程序;
}
静态IEnumerable GetPipeLine(t消费者,IComponentContext范围)
{
var pipeLine=consumer.GetType()
.GetTypeInfo().GetAttributes()
.OrderBy(attribute=>attribute.Order)
.Select(attribute=>attribute.Initialize((ipippe)scope.Resolve(attribute.PipeType)))
.Union(scope.ResolveNamed(GlobalPipeTag),a=>a.GetType());//在联合中对GetType执行区分,这样我们只会得到1个相同类型的处理程序
回流管道;
}
[HandleProcessCorruptedStateExceptions]
公共无效调度(TMessage消息)
where-TMessage:class
where t消费者:i消费者
{
使用(var scope=_component.BeginLifetimeScope(permessagelifetimescope标记,_contextFactory.RegisterMessageContext(typeof(TConsumer),message)))
{
var consumer=scope.Resolve();
var pipeLine=GetPipeLine(consumer,scope).ToArray();
pipeLine.Each(p=>p.onbeforecompose(consumer,message));
异常=空;
尝试
{
consumer.consumer(消息);
}
当(GetErrorHandlers(consumer,scope).Any(p=>p.OnError(consumer,message,e)),捕获(异常e)
{
例外=e;
}
prepipeline.Reverse().Each(p=>p.OnAfterConsume(使用者、消息、异常));
}
}
[HandleProcessCorruptedStateExceptions]
公共异步任务分派异步(TMessage消息)
where-TMessage:class
where TConsumer:IConsumeAsync
{
使用(var scope=_component.BeginLifetimeScope(permessagelifetimescope标记,_contextFactory.RegisterMessageContext(typeof(TConsumer),message)))
{
var consumer=scope.Resolve();
var pipes=GetPipeLine(consumer,scope).ToArray();
异常=空;
foreach(管道中的var钩)
wait hook.onbeforecumesync(消费者,消息);
尝试
{
等待消费者。消费(信息);
}
当(GetErrorHandlers(consumer,scope).Any(p=>p.OnErrorAsync(consumer,message,e))时捕获(异常e)
{
例外=e;
}
foreach(管道中的var hook.Reverse())
wait hook.onAfterConsumeSync(使用者、消息、异常);
}
}
}        
公共接口IMessageContextFactory
{
Action RegisterMessageContext(类型consumerType,TMessage message),其中TMessage:class;
}
[AttributeUsage(AttributeTargets.Class,AllowMultiple=true)]
公共类ErrorHandlerAttribute:属性
{
公共ErrorHandlerAttribute(类型errorHandlerType,整数顺序=0)
{
ErrorHandlerType=ErrorHandlerType;
订单=订单;
}
公共类型ErrorHandlerType{get;set;}
公共整数顺序{get;set;}
公共虚拟IErrorHandler初始化(IErrorHandler)
{
返回处理程序;
}
}
公共接口处理器
{
bool OnError(t消费者消费者、TMessage消息、异常)
where-TMessage:class
其中t消费者:i消费者;
bool OnErrorAsync(TConsumer consumer、TMessage消息、异常)
where-TMessage:class
其中t消费者:IConsumeAsync;
}
[AttributeUsage(AttributeTargets.Class,AllowMultiple=true)]
公共类PipeAttribute:Attribute
{
公共管道属性(管道类型,整数顺序=0)
{
管道类型=管道类型;
订单=订单;
}
公共类型管道类型{get;set;}
公共整数顺序{get;set;}
公共IPipe初始化(IPipe管道)
{
public class UnitOfWorkDecorator<TRequest, THandler> : IHandler<TRequest>
        where TRequest : class
        where THandler : IHandler<TRequest>
    {
        protected readonly Func<ILifetimeScope> ParentScope;

        public UnitOfWorkDecorator(Func<ILifetimeScope> parentScope)
        {
            ParentScope = parentScope;
        }

        public void Handle(TRequest request)
        {
            Console.WriteLine("UoW handler start");

            using (var scope = ParentScope().BeginLifetimeScope())
            {
                var scopedHandler = scope.Resolve<THandler>();
                scopedHandler.Handle(request);
            }

            Console.WriteLine("UoW handler end");
        }
    }
   [Test]
    public void UnitOfWork()
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<MessageCommandHandler>().As<IHandler<Message>>().InstancePerLifetimeScope();
        builder.RegisterType<MessageCommandHandler2>().As<IHandler<Message>>().InstancePerLifetimeScope();

        builder.RegisterGeneric(typeof(UnitOfWorkDecorator<,>)).AsSelf().SingleInstance();

        var container = builder.Build();

        var handler = container.Resolve<IHandler<Message>>();

        var uow = container.Resolve<UnitOfWorkDecorator<Message, IHandler<Message>>>();
        uow.Handle(new Message());

    }