Пример #1
0
        /// <summary>
        /// Read the contents of a file into a byte array, with the specified timeout and CancellationTokenSource
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="timeoutSeconds"></param>
        /// <param name="tokenSource"></param>
        /// <returns></returns>
        public static async Task <perTaskResult <byte[]> > ReadAllBytesFromFileAsync(
            string fileName,
            int timeoutSeconds,
            CancellationTokenSource tokenSource)
        {
            using (var file = OpenFileForAsyncReading(fileName))
            {
                var bytes = new byte[file.Length];

                var response = await file.ReadAsync(bytes, 0, (int)file.Length, tokenSource.Token)
                               .RunTaskWithTimeoutAsync(timeoutSeconds, tokenSource).ConfigureAwait(false);

                var result = new perTaskResult <byte[]>
                {
                    Status       = response.Status,
                    ErrorMessage = response.ErrorMessage,
                    Exception    = response.Exception
                };

                if (response.Status == perTaskStatus.CompletedOk)
                {
                    result.Data = bytes;
                }

                return(result);
            }
        }
        /// <summary>
        /// run a Task T  with the specified timeout / cancellation token and return the result
        /// </summary>
        public static async Task <perTaskResult <T> > GetTaskResultWithTimeoutAsync <T>(this Task <T> theTask, int timeoutSeconds, CancellationTokenSource tokenSource)
        {
            var taskResult = await theTask.RunTaskWithTimeoutAsync(timeoutSeconds, tokenSource).ConfigureAwait(false);

            var result = new perTaskResult <T>
            {
                Status       = taskResult.Status,
                Exception    = taskResult.Exception,
                ErrorMessage = taskResult.ErrorMessage
            };

            // the task has already completed if status is CompletedOk, but using await once more is better than using theTask.Result
            if (result.Status == perTaskStatus.CompletedOk)
            {
                result.Data = await theTask.ConfigureAwait(false);
            }

            return(result);
        }
        /// <summary>
        /// run a task with the specified timeout and cancellation token
        /// </summary>
        /// <remarks>
        /// tokenSource Parameter is CancellationTokenSource rather than CancellationToken as we want to trigger it in order to cancel
        /// theTask (assuming it's using the same CancellationTokenSource or its token) in the event of a timeout.
        /// </remarks>
        public static async Task <perTaskResult> RunTaskWithTimeoutAsync(this Task theTask, int timeoutSeconds, CancellationTokenSource tokenSource)
        {
            var result = new perTaskResult();

            // this will kill the timeout task, if the external cancellation token source is cancelled
            using (var timeoutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(tokenSource.Token))
            {
                var timeoutTask = timeoutSeconds == 0
                    ? Task.Delay(TimeSpan.FromMilliseconds(-1), timeoutTokenSource.Token)
                    : Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), timeoutTokenSource.Token);

                var completedTask = await Task.WhenAny(theTask, timeoutTask).ConfigureAwait(false);

                if (tokenSource.IsCancellationRequested)
                {
                    result.Status = perTaskStatus.Cancelled;
                }
                else if (completedTask == timeoutTask)
                {
                    result.Status = perTaskStatus.TimedOut;

                    // signal theTask to cancel if possible
                    tokenSource.Cancel();
                }
                else if (theTask.IsFaulted)
                {
                    result.Status       = perTaskStatus.Error;
                    result.Exception    = theTask.Exception;
                    result.ErrorMessage = theTask.Exception?.GetText();
                }
                else
                {
                    result.Status = perTaskStatus.CompletedOk;
                }

                // kill the timeoutTask if it's not already cancelled
                timeoutTokenSource.Cancel();
            }

            return(result);
        }