// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Diagnostics; using System.Text; using System.Threading.Tasks; namespace Microsoft.SqlTools.Hosting.Utility { public static class TaskExtensions { /// /// Adds handling to check the Exception field of a task and log it if the task faulted /// /// /// This will effectively swallow exceptions in the task chain. /// /// The task to continue /// /// An optional operation to perform after exception handling has occurred /// /// Task with exception handling on continuation public static Task ContinueWithOnFaulted(this Task antecedent, Action continuationAction) { return antecedent.ContinueWith(task => { // If the task hasn't faulted or has an exception, skip processing if (!task.IsFaulted || task.Exception == null) { return; } LogTaskExceptions(task.Exception); // Run the continuation task that was provided try { continuationAction?.Invoke(task); } catch (Exception e) { Logger.Write(TraceEventType.Error, $"Exception in exception handling continuation: {e}"); Logger.Write(TraceEventType.Error, e.StackTrace); } }); } /// /// Adds handling to check the Exception field of a task and log it if the task faulted. /// This version allows for async code to be ran in the continuation function. /// /// /// This will effectively swallow exceptions in the task chain. /// /// The task to continue /// /// An optional operation to perform after exception handling has occurred /// /// Task with exception handling on continuation public static Task ContinueWithOnFaulted(this Task antecedent, Func continuationFunc) { return antecedent.ContinueWith(task => { // If the task hasn't faulted or doesn't have an exception, skip processing if (!task.IsFaulted || task.Exception == null) { return; } LogTaskExceptions(task.Exception); // Run the continuation task that was provided try { continuationFunc?.Invoke(antecedent).Wait(); } catch (Exception e) { Logger.Write(TraceEventType.Error, $"Exception in exception handling continuation: {e}"); Logger.Write(TraceEventType.Error, e.StackTrace); } }); } private static void LogTaskExceptions(AggregateException exception) { // Construct an error message for an aggregate exception and log it StringBuilder sb = new StringBuilder("Unhandled exception(s) in async task:"); foreach (Exception e in exception.InnerExceptions) { sb.AppendLine($"{e.GetType().Name}: {e.Message}"); sb.AppendLine(e.StackTrace); } Logger.Write(TraceEventType.Error, sb.ToString()); } } }