Async класс для работы с BackgroundWorker в .net (альтернатива async/await)

Обобщенная схема разработанного дополнения выглядит следующим образом.

C# async worker

При разработке классов хотелось, чтобы их можно было использовать для работы с любыми типами данных. Идея и первая версия была реализована в 2011 году. WorkRequest представляет из себя класс для "запроса" на работу в некоторый исполнитель AsyncWorker (которых может быть целый пул AsyncWorkerPool). Исполнитель выполняет работу в фотоновом потоке, используя BackgroundWorker и по необходимости уведомляет UI слой об изменениях, используя UIWorkRequest. После выполнения работы исполнитель вызывает callback и передает в него результат работы WorkResponse.

Пример использования

Использовать реализованное решение можно во многих областях. Рассмотрим пример асинхронной отправки email сообщений пользователям. Например это может быть массовая рассылка. В этом примере я сознательно опускаю некоторые моменты для упрощения примера. Это сбор ошибок и само отправление email сообщения на C#, думаю это не вызовет проблем при использовании.

Объявляем типы.

/// <summary>
///   Метод для обновления UI
/// </summary>
private static Action<UIWorkRequest> _updateUI;


/// <summary>
///   Пул для стековых задач (в 1 элемент)
/// </summary>
private static AsyncWorkerPool _pool;

Метод назначения задач и старта рассылки

/// <summary>
/// Метод, рассылающий email сообщения подписчикам
/// </summary>
public static void SendMessages(List<Subscription> list, string subject, string message, Action<WorkResponse> callback)
{
    int count = list.Count;
    int currentSent = 0;
    
    for (int i = 0; i < list.Count; i++)
    {
        WorkRequest request = new WorkRequest(list[i]);
        //Указываем сколько процентов общей работы будет выполнено конкретной задачей
        request.UIWorkRequest.UIProgressValue = (i + 1) * 100 / count;
        //Заголовок для обозначения работы
        request.UIWorkRequest.UIWorkName = "Отправка сообщения";
        //Описание задачи (это будет email получателя)
        request.UIWorkRequest.UIWorkDescription = list[i].Email;
        
        if (i == count - 1)
            _pool.AddWork(SendMessagesAsync, callback, _updateUI, request);
        else
            //Во всех задачах кроме последней не требуется уведомление о полностью завершенном задании
            _pool.AddWork(SendMessagesAsync, null, _updateUI, request);
    }
}

Отправка сообщения (SendMessageAsync)

private static WorkResponse SendMessagesAsync(WorkRequest request)
{
    Subscription subscription = request.WorkObject as Subscription;
    bool sendResult = SendMailMessage(subscription, _subject, _message);
    return null;
}

Обновление информации о статусе рассылки

/// <summary>
///   Обновить информацию в окне ожидания
/// </summary>
private void FastUpdateAsyncUI(UIWorkRequest updateUIData)
{
    progress.Value = updateUIData.UIProgressValue;
    textBlockName.Text = updateUIData.UIWorkName;
    textBlockDescr.Text = updateUIData.UIWorkDescription;
}

Завершение отправки

private void SendComplete(WorkResponse response)
{
    progress.Value = 100;
    textBlockName.Text = "Отправка завершена";
    textBlockDescr.Text = "Все сообщения отправлены";
}

Таким образом исполнителю не важно знать что-либо о работе. Он должен инициировать ее выполнение и уведомить клиента о том, что работа выполнена. 

Этой записью я открываю публичный репозиторий с классами для работы в .NET. Постепенно буду наполнять библиотеку полезными в работе классами и методами. https://bitbucket.org/oxozle/utilities

Комментарии

comments powered by Disqus