C# Autofac EasyNetQ:工作单元
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())
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());
}