ASP.NET MVC中如何从Azure Service Bus队列取消息并展示到View.cshtml
问题描述
我有一个能从Azure Service Bus队列获取消息的控制台应用,代码如下:
using System; using System.Text; using System.Text.Json; using Microsoft.Azure.ServiceBus; using SampleShared.Models; namespace SampleAppReceiver { class Program { const string connString = "<my_connection_string>"; static IQueueClient qClient; static async Task Main(string[] args) { qClient = new QueueClient(connString, "<my_queue_name>"); var msgOptions = new MessageHandlerOptions(ExceptionReceivedHandler) { // 同时处理的消息数量 MaxConcurrentCalls = 1, // 等待消息完全处理后再自动完成 AutoComplete = false, }; qClient.RegisterMessageHandler(ProcessMessageAsync, msgOptions); Console.ReadLine(); await qClient.CloseAsync(); } private static async Task ProcessMessageAsync(Message msg, CancellationToken token) { // 反序列化消息体 var jsonBody = Encoding.UTF8.GetString(msg.Body); var personObj = JsonSerializer.Deserialize<Person>(jsonBody); Console.WriteLine($"Login: {personObj.Login}"); Console.WriteLine($"Message: {personObj.Message}"); // 通知队列消息已处理完成 await qClient.CompleteAsync(msg.SystemProperties.LockToken); } private static Task ExceptionReceivedHandler(ExceptionReceivedEventArgs args) { Console.WriteLine($"出现错误: {args.Exception}"); return Task.CompletedTask; } } }
目前我的ASP.NET MVC项目已经通过IAzureBusService接口实现了从View向Azure Service Bus队列发送消息的功能,相关代码如下:
// ... public interface IAzureBusService { Task SendMessageAsync(Person personMessage, string queueName); } // ...
对应的控制器方法:
[HttpPost] public async Task<IActionResult> Index(Person person) { await _busService.SendMessageAsync(person, "personqueue"); return RedirectToAction("Index"); }
请问如何在控制器中正确将从队列接收的所有消息添加到View.cshtml中?
解决方案
1. 扩展Azure Bus服务接口
首先给IAzureBusService添加接收消息的方法,支持一次性拉取多条消息:
public interface IAzureBusService { Task SendMessageAsync(Person personMessage, string queueName); // 添加拉取消息的方法,参数为队列名和拉取数量 Task<List<Person>> ReceiveMessagesAsync(string queueName, int messageCount = 10); }
2. 实现消息接收逻辑
在IAzureBusService的实现类中,添加消息接收的具体代码。这里使用ReceiveAsync方法拉取指定数量的消息,处理完成后标记为已完成(从队列移除):
public class AzureBusService : IAzureBusService { private readonly string _connectionString; public AzureBusService(IConfiguration configuration) { _connectionString = configuration.GetValue<string>("AzureServiceBus:ConnectionString"); } // 原有发送消息的实现... public async Task<List<Person>> ReceiveMessagesAsync(string queueName, int messageCount = 10) { var receivedPersons = new List<Person>(); using var queueClient = new QueueClient(_connectionString, queueName); try { // 拉取指定数量的消息,超时时间设置为5秒 var messages = await queueClient.ReceiveAsync(messageCount, TimeSpan.FromSeconds(5)); foreach (var message in messages) { // 反序列化消息体 var jsonBody = Encoding.UTF8.GetString(message.Body); var person = JsonSerializer.Deserialize<Person>(jsonBody); receivedPersons.Add(person); // 标记消息为已处理,从队列移除 await queueClient.CompleteAsync(message.SystemProperties.LockToken); } } catch (Exception ex) { // 这里可以添加日志记录逻辑 Console.WriteLine($"接收消息出错: {ex.Message}"); } finally { await queueClient.CloseAsync(); } return receivedPersons; } }
如果你只想查看消息而不将其从队列移除,可以使用
PeekAsync方法替代ReceiveAsync,这样消息会保留在队列中供后续处理。
3. 在控制器中调用接收方法并传递给View
修改控制器的Index方法,在GET请求时拉取队列消息,将消息列表传给View:
public class HomeController : Controller { private readonly IAzureBusService _busService; public HomeController(IAzureBusService busService) { _busService = busService; } public async Task<IActionResult> Index() { // 拉取队列中的消息,最多10条 var receivedMessages = await _busService.ReceiveMessagesAsync("personqueue"); // 将消息列表传给View return View(receivedMessages); } [HttpPost] public async Task<IActionResult> Index(Person person) { await _busService.SendMessageAsync(person, "personqueue"); return RedirectToAction("Index"); } }
4. 在View中展示消息
修改Index.cshtml,使用模型绑定展示接收到的消息列表:
@model List<SampleShared.Models.Person> <h1>消息列表</h1> @if (Model != null && Model.Count > 0) { <table class="table"> <thead> <tr> <th>Login</th> <th>消息内容</th> </tr> </thead> <tbody> @foreach (var person in Model) { <tr> <td>@person.Login</td> <td>@person.Message</td> </tr> } </tbody> </table> } else { <p>暂无消息</p> } <h2>发送新消息</h2> <form asp-action="Index" method="post"> <div class="form-group"> <label>Login</label> <input type="text" name="Login" class="form-control" /> </div> <div class="form-group"> <label>消息内容</label> <textarea name="Message" class="form-control"></textarea> </div> <button type="submit" class="btn btn-primary">发送</button> </form>
补充说明
如果需要实时接收并展示消息(无需刷新页面),可以结合SignalR实现:
- 后台启动一个服务持续监听队列,当有新消息时通过SignalR推送给前端
- 前端页面通过SignalR连接接收消息并动态更新UI
这种方式更适合需要实时展示的场景,但实现复杂度更高。
内容的提问来源于stack exchange,提问作者np.
相关产品推荐
相关产品推荐

