public static void Patch(this BulkActionPushNotification target, BulkActionProgressContext source)
 {
     target.Description    = source.Description;
     target.Errors         = source.Errors;
     target.ProcessedCount = source.ProcessedCount;
     target.TotalCount     = source.TotalCount;
 }
        public virtual async Task ExecuteAsync(BulkActionContext context,
                                               Action <BulkActionProgressContext> progressAction,
                                               ICancellationToken token)
        {
            // initialize the common context
            _progressAction  = progressAction;
            _token           = token;
            _progressContext = new BulkActionProgressContext {
                Description = "Validation has started…"
            };
            var totalCount     = 0;
            var processedCount = 0;

            // begin
            ValidateContext(context);
            SendFeedback();

            try
            {
                var action = GetAction(context);
                await ValidateActionAsync(action);

                SendFeedback();

                var dataSource = GetDataSource(context);
                totalCount = await dataSource.GetTotalCountAsync();

                SetProcessedCount(processedCount);
                SetTotalCount(totalCount);
                SetDescription("The process has been started…");
                SendFeedback();

                while (await dataSource.FetchAsync())
                {
                    ThrowIfCancellationRequested();

                    var result = await action.ExecuteAsync(dataSource.Items);

                    if (result.Succeeded)
                    {
                        // idle
                    }
                    else
                    {
                        SetErrors(result.Errors);
                    }

                    processedCount += dataSource.Items.Count();
                    SetProcessedCount(processedCount);

                    if (processedCount == totalCount)
                    {
                        continue;
                    }

                    SetDescription($"{processedCount} out of {totalCount} have been updated.");
                    SendFeedback();
                }
            }
            catch (Exception exception)
            {
                SetError(exception.Message);
            }
            finally
            {
                const string ErrorsMessage   = "The process has been completed with errors";
                const string CompleteMessage = "Process is completed";
                var          message         = IsContainsErrors() ? ErrorsMessage : CompleteMessage;
                SetDescription($"{message}: {processedCount} out of {totalCount} have been updated.");
                SendFeedback();
            }
        }