Как уведомить приложение AngularJS от EasyNetQ

Таким образом, у меня есть следующая архитектура: Angular SPA (одностраничное приложение) выполняет вызов к контроллеру.NET Web API, который публикует сообщение в оконную службу EasyNetQ Publisher, которая отправляет асинхронный запрос во вторую оконную службу 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);
    }
}

Вот как я отправляю запрос от издателя:

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 остается. Есть идеи?

1 ответ

Решение

Прежде всего обратите внимание, что вы должны где-то хранить информацию о состоянии отчета. Вы можете хранить его в двух местах:

  • Постоянное хранилище (база данных, Redis кеш, что угодно).
  • В памяти сервиса web api (потому что именно с этим сервисом общается клиент).

Когда вы решили, где хранить - снова есть два варианта передачи этой информации клиенту:

  • Клиент (Angular) может время от времени опрашивать (обратите внимание, что это не то, что называется "длинным опросом"). Если вы храните свой статус в базе данных - вы можете просто посмотреть его в этом случае.

  • Существует постоянная связь между Angular и вашим API (веб-сокеты, длинный опрос также падает здесь). В этом случае вам лучше сохранить свой статус в памяти веб-API (передавая сообщение кролика со статусом отчета из вашего сервиса веб-API, которое затем сохраняет его в памяти и \ или напрямую передает его в Angular через постоянное соединение).

Если вы не ожидаете клиентов на разных платформах (iOS, чистый Linux и т. Д.) - SignlarR может работать нормально. Он переключится с веб-сокетов на длительный опрос и регулярный опрос в зависимости от возможностей браузера пользователя.

Другие вопросы по тегам