Реализация событий Server-Sider с SignalR - PullRequest
0 голосов
/ 08 ноября 2018

В настоящее время я работаю над созданием некоторых концепций SignalR для некоторых из наших текущих инструментов, и я ищу лучший подход для реализации какой-либо серверной платформы событий. Многие из наших инструментов очень процедурные и простые, но у меня есть некоторые долгосрочные задачи, которые я хочу изменить вокруг.

Одним из таких примеров является наша платформа отчетности. У нас есть собственная базовая система отчетности, встроенная в наше веб-приложение, которая выполняет некоторые готовые отчеты. Эти отчеты могут занять от 30 секунд до 5 минут. Они запускаются путем отправки запроса на сервер с необходимыми параметрами. Как только сервер получает запрос, он возвращает уникальный идентификатор обратно клиенту. Затем сервер запускает обработчик отчетов, который в основном представляет собой небольшой нежелательный асинхронный метод, который выполняет некоторые функции и устанавливает состояние отчета в базе данных.

В настоящее время существует механизм опроса на стороне клиента, который периодически запрашивает у сервера состояние отчета, и после запуска отчета он выбирает и отображает отчет. Я переключил методы работы с отчетами и изменил их, чтобы запустить механизм опроса на стороне сервера, который постоянно проверяет базу данных в другом потоке. Как только отчет завершен, он вызывает наш концентратор signalR и передает его клиенту.

Я пытаюсь найти способ изменить сервер, вместо того чтобы опрашивать его, чтобы получить статус, вместо этого каким-то образом подключиться к обработчику отчетов и затем вызвать концентратор signalR, когда он будет завершен.

Моя текущая идея - сделать необязательный параметр для бегуна, который принимает объект, который реализует простой интерфейс, IBasicEvent. Этот интерфейс может выглядеть примерно так:

public interface IBasicEvent
{
    void OnSuccess();
    void OnError();
    void Complete();
}

Оттуда я мог бы реализовать интерфейс в своем проекте WebUI и просто передать его в обработчик отчетов в моем другом проекте. Это кажется относительно простым, но я также видел некоторую информацию о возможном использовании делегатов, почти как обратных вызовов в javascript. Я действительно не уверен, что лучший подход здесь.

1 Ответ

0 голосов
/ 08 ноября 2018

Мне удалось получить довольно крутое подтверждение концепции, используя делегаты C # и обработчики событий, которые, кажется, обрабатывают все, что мне нужно. Вот базовая установка с несоответствующей логикой.

В моем отчете:

public class ReportRunner
{
    public delegate Task RunCompleteHandler(ReportRunner runner, ReportStatusEventArgs eventArgs);
    public event RunCompleteHandler RunComplete;

    protected void OnRunComplete(ReportRunner runner, ReportStatusEventArgs eventArgs)
    {
        RunComplete?.Invoke(runner, eventArgs);
    }

    private async Task ExecuteReport(FilterSet filters, Guid guid)
    {
        try
        {
            // run the report
        }
        catch (Exception ex)
        {
            // log and set the report to error status
        }
        finally
        {
            var status = _reportLogic.GetReportRunStatus(guid);
            var eventArgs = new ReportStatusEventArgs(status);

            OnRunComplete(this, eventArgs);
        }
    }
}

public class ReportStatusEventArgs : EventArgs
{
    public readonly ReportRunStatus ReportRunStatus;
    public ReportStatusEventArgs(ReportRunStatus reportRunStatus)
    {
        ReportRunStatus = reportRunStatus;
    }
}

И в моем контроллере:

public async Task<IActionResult> Run(FiltersRequest request)
{
    // basic checks omitted
    var factory = new ReportFactory();
    var reportModel = factory.CreateReport(reportType);
    var runner = new ReportRunner(reportModel, _contexts);
    var eventHandler = new ReportRunnerSubscriber(_reportHub, HttpContext.User.Identity.Name);
    eventHandler.Subscribe(runner);

    var guid = await runner.Run(filterSet);

    return Json(guid);
}

И мой абонентский класс

public class ReportRunnerSubscriber
{
    private readonly IHubContext<ReportHub> _reportHub;
    private readonly string _userId;

    public ReportRunnerSubscriber(IHubContext<ReportHub> reportHub, string userId)
    {
        _reportHub = reportHub;
        _userId = userId;
    }

    public void Subscribe(ReportRunner reportRunner)
    {
        reportRunner.RunComplete += NotifySubscribers;
    }

    public async Task NotifySubscribers(ReportRunner reportRunner, ReportStatusEventArgs eventArgs)
    {
        var status = eventArgs.ReportRunStatus;
        status.ReportRuns = null;
        await _reportHub.Clients.User(_userId).SendAsync("ReportComplete", status);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...