我有一个Web应用程序,该应用程序通过Azure服务总线发送消息并等待答复:
var response = await this.createClient.GetResponse<Models.Response<CommandResponse>>(message, cancellationToken);
我有一个带有服务总线触发器的Azure功能,该触发器使用消息:
[FunctionName("CommandHandler")]
public Task HandleCommandAsync(
[ServiceBusTrigger("input-queue", Connection = "AzureWebJobsServiceBus"), ServiceBusAccount("ServiceBus")]
Message message,
IBinder binder,
ILogger logger,
CancellationToken cancellationToken)
{
logger.LogInformation("Command Handler Function Invoked.");
var result = System.Text.Encoding.UTF8.GetString(message.Body);
var d = JsonConvert.DeserializeObject<dynamic>(result);
string messageType = d.message.messageType.Value;
var handler = Bus.Factory.CreateBrokeredMessageReceiver(
binder,
cfg =>
{
cfg.CancellationToken = cancellationToken;
cfg.SetLog(logger);
cfg.InputAddress = new Uri($"{this.secrets.Value.ServiceBusUri}/input-queue");
cfg.UseRetry(x => x.Intervals(10, 100, 500, 1000));
cfg.Consumer(() => this.customerConsumer);
});
var handlerResult = handler.Handle(message);
logger.LogInformation("Command Handler Function Completed.");
return handlerResult;
}
为了从Web应用程序发送消息,我必须配置使用者。我不确定为什么要这样做,因为Web应用程序永远不需要直接引用使用者,但是如果没有以下代码,则不会发送任何消息。
services.AddMassTransit(
x =>
{
x.AddConsumer<CustomerConsumer>();
x.AddBus(
provider => Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
var host = cfg.Host(secrets.AzureWebJobsServiceBus, h => { });
cfg.ReceiveEndpoint(
host,
"input-queue",
ep =>
{
ep.ConfigureConsumer<CustomerConsumer>(provider);
ep.PrefetchCount = 16;
ep.UseMessageRetry(r => r.Interval(2, 100));
});
}));
x.AddRequestClient<RegisterNewCustomerCommand>();
});
问题出在消息发送后,有时 CommandHandler
函数应用触发并调用了使用者的Handle
消息。
但是有时有时Web应用程序无意中直接调用了使用者(因为使用者在启动时已注册并正在队列中侦听消息)。
这是我所不希望的。为了实现可伸缩性,只有Azure功能可以调用使用者。此外,使用者具有注入的依赖项,这些依赖项仅在功能应用程序的WebHostStartUp
中注册,因此如果直接从Web应用程序中调用,则使用者会出错。
问题:如何打破Web应用程序与使用者之间的依赖关系,以使它们永远不会被Web应用程序直接调用而是由功能应用程序触发器直接调用?我有什么办法可以避免在Web App的StartUp方法中添加/配置使用者,同时仍然使Web App能够通过GetResponse
发送消息?
更新-解决方案
ASP.NET Core 2.2启动不需要对使用者的任何引用(除非与我不同,您希望Web应用程序也使用消息)。
您需要将包括队列路径的服务总线URL添加到AddRequestClient
。查看接受的答案。
这对我有用。
services.AddMassTransit(
x =>
{
x.AddBus(
provider => Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
cfg.Host(
secrets.AzureWebJobsServiceBus,
h => { h.TransportType = TransportType.Amqp; });
}));
var serviceBusUri = new Uri($"{settings.ServiceBusUri}/input-queue");
x.AddRequestClient<RegisterNewCustomerCommand>
});
}
答案 0 :(得分:1)
您不需要让使用者使用您的客户端API。我唯一能想到的是您没有正确的拓扑设置。
AddRequestClient
调用中将其指定为参数(_sb://host..../input-queue)。由于配置请求客户端的方式,很可能是使用发布而不是发送,因为它不知道队列地址。在这种情况下,将使用者添加到您的Web API会对该主题进行适当的订阅,以将消息转发到队列。您可以使用Service Bus Explorer之类的工具查看所有内容在云中的布局。
将URI添加到请求客户端的客户端应用程序应该可以解决该问题,并将命令直接发送到队列。