【问题标题】:How to notify AngularJS application from EasyNetQ如何从 EasyNetQ 通知 AngularJS 应用程序
【发布时间】:2016-09-20 19:22:13
【问题描述】:

所以我有以下架构:Angular SPA(单页应用程序)执行对 .NET Web API 控制器的调用,该控制器将消息发布到 Publisher EasyNetQ 窗口服务,该服务将异步请求发送到第二个 EasyNetQ 窗口服务名为 Subscriber,它调用后端类生成 SSRS 报告,最后将异步响应发送回 Publisher。以下是相关架构的示意图:

到目前为止一切顺利,订阅者收到响应,生成报告,并将消息发送回发布者。以下是 Web API 控制器将报告数据消息发送到发布者的方式:

private IHttpActionResult generateReports(int[] incidentIds)
{
    try
    {
        var incident = this.incidentRepository.GetIncident(incidentIds[0]);
        var client = this.clientService.GetClient(incident.ClientId_Fk);

        using (var messageBus = RabbitHutch.CreateBus("host=localhost"))
        {
            // Loop through all incidents
            foreach (var incidentId in incidentIds)
            {

                foreach (var format in this.formats)
                {
                    Dictionary<Dictionary<int, Client>, SSRSReportFormat> reportData = new Dictionary
                        <Dictionary<int, Client>, SSRSReportFormat>()
                        {
                            {new Dictionary<int, Client>() {{incidentId, client}}, format}
                        };

                    messageBus.Publish(new ReportData
                    {
                        clientId = client.Id,
                        incidentId = incidentId,
                        clientName = client.Name,
                        clientNetworkPath = client.NetworkPath,
                        formatDescription = EnumUtils.GetDescription(format),
                        reportFormat = format.ToString()
                    });                            
                }
            }
        }

        return this.Ok();
    }
    catch (Exception ex)
    {
        return this.InternalServerError(ex);
    }
}

这是我从 Publisher 发送请求的方式:

public partial class CreateRequestService : ServiceBase
{
    private IBus bus = null;

    public CreateRequestService()
    {
        this.InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        this.bus = RabbitHutch.CreateBus("host=localhost");

        this.bus.Subscribe<ReportData>("reportHandling", this.HandleReportData);
    }

    protected override void OnStop()
    {
        this.bus.Dispose();
    }

    private void HandleReportData(ReportData reportData)
    {
        int clientId = reportData.clientId;
        int incidentId = reportData.incidentId;
        string clientName = reportData.clientName;
        string clientNetworkPath = reportData.clientNetworkPath;
        string formatDescription = reportData.formatDescription;
        string reportFormat = reportData.reportFormat;

        var task = this.bus.RequestAsync<ReportData, TestResponse>(reportData);
        task.ContinueWith(response => Library.WriteErrorLog("Got response: '{0}'" + response.Result.Response, "PublisherLogFile"));

    }
}

最后,生成报告并从订阅者返回响应的代码:

public partial class RequestResponderService : ServiceBase
{
    private IBus bus = null;

    public RequestResponderService()
    {
        this.InitializeComponent();
    }

    /// <summary>
    /// Initialize the Bus to receive and respond to messages through
    /// </summary>
    /// <param name="args"></param>
    protected override void OnStart(string[] args)
    {
        // Create a group of worker objects
        var workers = new BlockingCollection<MyWorker>();
        for (int i = 0; i < 10; i++)
        {
            workers.Add(new MyWorker());
        }

        workers.CompleteAdding();

        // Initialize the bus
        this.bus = RabbitHutch.CreateBus("host=localhost");

        // Respond to the request asynchronously
        this.bus.RespondAsync<ReportData, TestResponse>(request =>
            (Task<TestResponse>) Task.Factory.StartNew(() =>
            {
                var worker = workers.Take();

                try
                {
                    return worker.Execute(request);
                }
                catch (Exception)
                {

                    throw;
                }
                finally
                {
                }
            }));
    }

    protected override void OnStop()
    {
        this.bus.Dispose();
    }        
}

class MyWorker
{
    public TestResponse Execute(ReportData request)
    {
        int clientId = request.clientId;
        int incidentId = request.incidentId;
        string clientName = request.clientName;
        string clientNetworkPath = request.clientNetworkPath;
        string formatDescription = request.formatDescription;
        string reportFormat = request.reportFormat;

        ReportQuery reportQuery = new ReportQuery();
        reportQuery.Get(incidentId, reportFormat, formatDescription, clientName, clientNetworkPath, clientId);

        return new TestResponse { Response = " ***** Report generated for client: " + clientName + ", incident Id: " + incidentId + ", and format: " + reportFormat + " ***** " };
    }
}

虽然这一切都有效,但我还需要某种方式来通知 Angular SPA 已生成报告,以便我可以向用户提供适当的反馈。这是我有点失落的地方。 EasyNetQ 可以与 Angular 代码交互吗?此外,一旦我在 Publisher 中收到响应,我可能会在我的 Web API 控制器中调用一些方法,但仍然存在警告 Angular 代码的问题。有什么想法吗?

【问题讨论】:

  • 只有两个选项。第一个:客户端(anjular 应用程序)应不时轮询报告状态,而您的服务要么将报告生成进度存储在持久存储(数据库)中,要么通过兔子消息将其发布回存储在内存中的 web api。然后当客户端轮询 - web api 报告状态。第二:您实现了从 Angular 应用程序到 Web api 的持久通道(Web 套接字) - 然后您通知客户端而不进行轮询(再次首先将消息发送到 Web api 应用程序,然后通过 Websocket 将此消息发送到 anjular)。
  • 请查看SignalR:正如 Evk 所说,近实时通知系统的唯一选择是使用 Web Sockets 或长轮询。 SignalR 正是这样做的。
  • 太棒了!谢谢你们俩。现在研究 SignalR。你们中的一个(或两个)应该发布一个答案,以便我可以将其标记为已接受。

标签: c# .net asp.net-web-api rabbitmq easynetq


【解决方案1】:

首先请注意,您必须在某处存储有关报告状态的信息。您可以将其存储在两个地方:

  • 持久存储(数据库、redis 缓存等)。
  • web api 服务的内存中(因为客户端正在与之通信的是该服务)。

当您决定存储位置时 - 再次有两种选择如何将此信息传递给客户:

  • 客户端 (Angular) 可以不时进行轮询(注意它不是所谓的“长轮询”)。如果您将您的状态存储在数据库中 - 在这种情况下您可以在那里查找它。

  • Angular 和您的 api 之间存在持久连接(网络套接字、长轮询也属于此处)。在这种情况下,您最好将您的状态存储在 web api 的内存中(通过将带有报告状态的兔子消息从您的服务传递到 web api,然后将其存储在内存中并\或通过持久连接直接将其转发给 Angular)。

如果您不希望客户端使用不同的平台(iOS、纯 linux 等)-SignlarR 可以正常工作。它将根据用户浏览器的功能从 websockets 回退到长轮询到定期轮询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    相关资源
    最近更新 更多