如何从 EasyNetQ 通知 AngularJS 应用程序
How to notify AngularJS application from EasyNetQ
所以我有以下架构:Angular SPA(单页应用程序)执行对 .NET Web API 控制器的调用,该控制器将消息发布到发布者 EasyNetQ window 服务,它向称为订阅者的第二个 EasyNetQ window 服务发送异步请求,该服务调用后端 class 生成 SSRS 报告,最后将异步响应发送回发布者。这是相关架构的图表:
到目前为止一切顺利,订阅者收到响应,生成报告,并将消息发送回发布者。以下是 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);
}
}
这是我向发布者发送请求的方式:
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 代码的问题。有什么想法吗?
首先请注意,您必须在某处存储有关报告状态的信息。您可以将它存储在两个地方:
- 持久存储(数据库、redis 缓存等)。
- 纪念 web api 服务(因为客户端正在与之通信的是该服务)。
当您决定存储位置时 - 如何将此信息传递给客户也有两种选择:
客户端(Angular)可以时不时的轮询(注意是不是所谓的"long polling")。如果您将您的状态存储在数据库中 - 在这种情况下您可以在那里查找它。
Angular和你的api之间存在持久连接(网络套接字,长轮询也落在这里)。在这种情况下,你最好将你的状态存储在 web api 的内存中(通过将带有报告状态的兔子消息从你的服务传递到 web api,然后将其存储在内存 and\or 中直接转发通过持久连接到 Angular)。
如果您不希望客户端在不同平台上(iOS、纯 linux 等)- SignlarR 可以正常工作。它将根据用户浏览器的功能从 websockets 回退到长轮询再到定期轮询。
所以我有以下架构:Angular SPA(单页应用程序)执行对 .NET Web API 控制器的调用,该控制器将消息发布到发布者 EasyNetQ window 服务,它向称为订阅者的第二个 EasyNetQ window 服务发送异步请求,该服务调用后端 class 生成 SSRS 报告,最后将异步响应发送回发布者。这是相关架构的图表:
到目前为止一切顺利,订阅者收到响应,生成报告,并将消息发送回发布者。以下是 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);
}
}
这是我向发布者发送请求的方式:
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 代码的问题。有什么想法吗?
首先请注意,您必须在某处存储有关报告状态的信息。您可以将它存储在两个地方:
- 持久存储(数据库、redis 缓存等)。
- 纪念 web api 服务(因为客户端正在与之通信的是该服务)。
当您决定存储位置时 - 如何将此信息传递给客户也有两种选择:
客户端(Angular)可以时不时的轮询(注意是不是所谓的"long polling")。如果您将您的状态存储在数据库中 - 在这种情况下您可以在那里查找它。
Angular和你的api之间存在持久连接(网络套接字,长轮询也落在这里)。在这种情况下,你最好将你的状态存储在 web api 的内存中(通过将带有报告状态的兔子消息从你的服务传递到 web api,然后将其存储在内存 and\or 中直接转发通过持久连接到 Angular)。
如果您不希望客户端在不同平台上(iOS、纯 linux 等)- SignlarR 可以正常工作。它将根据用户浏览器的功能从 websockets 回退到长轮询再到定期轮询。