是否可以在没有管理权限策略的情况下将 MassTransit 3 与 Azure 服务总线一起使用?

Is it possible to use MassTransit 3 with Azure Service Bus without Manage permission policy?

我花了几天时间测试 MassTransit 3.1.2 看看我们是否可以在我们的应用程序中将它与 Azure 服务总线 一起使用。

我使用 MassTransit.AzureServiceBus (3.1.2) 制作了一个包含两个控制台应用程序的示例:一个发布者和一个订阅者。

效果很好。当我启动应用程序时,实体(队列、主题、订阅)会在我的 Azure 命名空间上自动创建。
这在测试时很好,但在生产中,我不希望应用程序被允许创建实体。我们想预先创建它们。

为了尝试,我认为使用 SAS 策略连接到总线是个好主意 "Send""Listen" 权限(在我使用具有 "Manage" 权限的名称空间策略之前)。

现在我在这一点上苦苦挣扎,我无法让它工作,我总是收到 401 错误 此操作需要管理声明 如果我不'使用具有 "Manage" 权限的策略。
我尝试直接在命名空间或实体上设置策略但没有成功。

之后我分析了堆栈跟踪异常(用[...]省略了无用的部分):

System.UnauthorizedAccessException: Le serveur distant a retourné une erreur : (401) Non autorisé. Manage claim is required for this operation. TrackingId:2ca420e3-aac6-467c-bacb-6e051dbc3e39_G47,TimeStamp:1/29/2016 11:20:41 PM ---> System.Net.WebException: Le serveur distant a retourné une erreur : (401) Non autorisé.
   à System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   à Microsoft.ServiceBus.Messaging.ServiceBusResourceOperations.GetAsyncResult`1.<GetAsyncSteps>b__3c(GetAsyncResult`1 thisPtr, IAsyncResult r)
   à Microsoft.ServiceBus.Messaging.IteratorAsyncResult`1.StepCallback(IAsyncResult result)
   --- Fin de la trace de la pile d'exception interne ---

Server stack trace:

Exception rethrown at [0]:
   à Microsoft.ServiceBus.Common.ExceptionDispatcher.Throw(Exception exception)
   à Microsoft.ServiceBus.Common.AsyncResult.End[TAsyncResult](IAsyncResult result)
   à Microsoft.ServiceBus.Common.AsyncResult`1.End(IAsyncResult asyncResult)
   à Microsoft.ServiceBus.Messaging.ServiceBusResourceOperations.EndGet[TEntityDescription](IAsyncResult asyncResult, String[]& resourceNames)
   à Microsoft.ServiceBus.NamespaceManager.EndGetQueue(IAsyncResult result)
   à System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
[...]
   à MassTransit.AzureServiceBusTransport.NamespaceManagerExtensions.<CreateQueueSafeAsync>d__1.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
[...]
   à MassTransit.AzureServiceBusTransport.Pipeline.PrepareReceiveQueueFilter.<Send>d__5.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
[...]
   à MassTransit.AzureServiceBusTransport.ServiceBusReceiveTransport.<>c__DisplayClass12_0.<<Receiver>b__0>d.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
[...]
   à MassTransit.Internals.Extensions.TaskExtensions.<WithCancellation>d__0`1.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception 
[...]
   à MassTransit.MassTransitBus.<StartAsync>d__30.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
   à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   à MassTransit.MassTransitBus.<StartAsync>d__30.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
   à System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   à System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   à MassTransit.Util.TaskUtil.Await[T](Func`1 taskFactory, CancellationToken cancellationToken)
   à MassTransit.MassTransitBus.MassTransit.IBusControl.Start()

我发现带有 MassTransit.AzureServiceBusTransport.NamespaceManagerExtensions.CreateQueueSafeAsync 的行非常有趣,因为我能够查看 MassTransit 源代码以了解内容它正在做。我看到它正在使用 NamespaceManager 进行一些调用以获取队列或主题。

由于这个 class 被命名为 NamespaceManager,我认为这意味着您无论如何都需要“Manage”权限。
为此,我制作了一个仅使用 Azure SDK 的基本控制台应用程序,以使用仅具有监听或发送权限的策略对 NamespaceManager 进行一些调用:我尝试的所有调用均出现 401 错误。添加管理权限有效。

我在 Azure 文档中没有找到关于此假设的任何信息,或者我可能遗漏了什么。

最后一个问题:

有没有办法在 Azure 服务总线上仅通过发送或侦听策略使用 MassTransit?我是不是错过了什么,我走错了路?

因为MassTransit负责管理服务总线命名空间的拓扑结构,包括创建主题和队列以及创建和绑定订阅,所以需要管理权限。

虽然您可能认为在生产环境中手动创建所有内容并将该权限保留在您的应用程序之外是个好主意,但您总是会花时间弄清楚生产环境中出现问题的原因并让您的工程师感到沮丧。我从这方面的经验谈起 -- 这就是我们需要许可的原因。

还有为总线管理创建的自动删除队列,这同样需要管理权限。

更新: 管理仍然是必需的,但是,您可能 能够绕过它。如果您可以提前创建主题、队列和订阅,并且将 MassTransit 配置为不创建主题、队列或订阅,并且可能不发布故障(除非您也打算创建这些主题),并且不使用错误或跳过队列。

例如,此配置基本上将 MassTransit 的使用限制为仅队列:

var bus = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
    cfg.Host(...);

    cfg.ReceiveEndpoint("existing-queue", e =>
    {
        e.PublishFaults = false;
        e.ConfigureConsumeTopology = false;

        e.ConfigureDeadLetterQueueErrorTransport();
        e.ConfigureDeadLetterQueueDeadLetterTransport();

        e.Consumer(...);
    });
});

直接发送到队列(queue:existing-queue 的 destinationAddress)的消息将被接收端点使用,并且 error/skipped 消息将被移动到 Azure 死信队列。如果存在与消息类型匹配的主题名称,则只能调用发布(或者您可以使用 topic:existing-topic-name 作为目标地址)。