如何在发送消息之前和之后以及处理消息之前和之后向Rebus消息处理管道添加中间件?

时间:2018-03-08 20:03:01

标签: rebus

我需要这个来简化以下典型的例行操作的实现:

  1. 我想在发送消息之前捕获用户的上下文,并在处理消息之前恢复用户上下文,类似于以下遗留示例中的操作方式:https://github.com/rebus-org/RebusSamples/tree/master/old/UserContextHeaders

  2. 我想在处理邮件之前对邮件进行验证和重复数据删除,并在处理邮件后记录结果。

1 个答案:

答案 0 :(得分:1)

正如问题作者正确找到的那样,Rebus.Events包提供了可读和可访问的方式,可以在发送/接收消息之前/之后挂钩。

如果这就足够了,我肯定会这样做。

但是,如果是你想WRAP try/finally内的单个消息的整个处理(我建议你在恢复发送用户的身份来处理消息时),你可能想看看基于本机的扩展机制关于装饰者。

您可以阅读the wiki page about extensibility,了解如何通过修改其管道来扩展Rebus。

例如,要在处理消息之前和之后对当前的声明主体执行某些操作,您可以实现这样的“传入管道步骤”:

[StepDocumentation("Write a nice descriptoion here")]
class MyIncomingStep : IIncomingStep
{
    public async Task Process(IncomingStepContext context, Func<Task> next)
    {
        var originalPrincipal = ClaimsPrincipal.Current;

        try 
        {
            // establish user identity here
            ClaimsPrincipal.Current = ...

            // handle message
            await next();
        }
        finally 
        {
            ClaimsPrincipal.Current = originalPrincipal;
        }
    }
}

然后您可以使用“步进注入器”装饰Rebus'IPipeline,声明性地说明您希望插入步骤的管道中的位置:

.Options(o => {
    o.Decorate<IPipeline>(c =>
    {
        var pipeline = c.Get<IPipeline>();
        var stepToInject = new TransactionScopeIncomingStep(transactionOptions);

        return new PipelineStepInjector(pipeline)
            .OnReceive(stepToInject, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep));
    });    
})

然后 - 为了让事情变得漂亮 - 你可以将上面的代码包含在OptionsConfigurer的扩展方法中,从而提供更漂亮的配置语法:

.Options(o => {
    o.RestoreClaimsPrincipalWhenHandlingMessages();
})

或者您认为应该被称为的任何内容:)

发送消息时,一切都以类似的方式工作,你只想

//....
return new PipelineStepInjector(pipeline)
     .OnSend(stepToInject, PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep));

代替。