diff --git a/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fs b/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fs new file mode 100644 index 00000000000..aed5876bf0d --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fs @@ -0,0 +1,58 @@ +// +open System +open System.IO +open System.Threading.Tasks + +let getAllFiles str = + // Should throw an UnauthorizedAccessException exception. + System.IO.Directory.GetFiles(str, "*.txt", System.IO.SearchOption.AllDirectories) + +// Get a folder path whose directories should throw an UnauthorizedAccessException. +let path = + let directory = + Environment.SpecialFolder.UserProfile + |> Environment.GetFolderPath + |> Directory.GetParent + directory.FullName + +// Use this line to throw an exception that is not handled. +// let task1 = Task.Factory.StartNew(fun () -> raise (IndexOutOfRangeException()) ) +let task1 = Task.Factory.StartNew(fun () -> getAllFiles (path)) + +let execute () = + try + task1.Wait() + with + | :? UnauthorizedAccessException -> printfn "Caught unauthorized access exception-await behavior" + | :? AggregateException as ae -> + printfn "Caught aggregate exception-Task.Wait behavior" + + ae.Handle (fun x -> + match x with + | :? UnauthorizedAccessException -> + printfn "You do not have permission to access all folders in this path." + printfn "See your network administrator or try another path." + true + | _ -> false) + printfn $"""task1 Status: {if task1.IsCompleted then "Completed," else ""}{task1.Status}""" + +execute () + +// The example displays the following output if the file access task is run: +// You do not have permission to access all folders in this path. +// See your network administrator or try another path. +// task1 Status: Completed,Faulted +// It displays the following output if the second task is run: +// Unhandled exception. System.AggregateException: One or more errors occurred. (Index was outside the bounds of the array.) (Index was outside the bounds of the array.) +// ---> System.IndexOutOfRangeException: Index was outside the bounds of the array. +// at Exception1.task1@19.Invoke() +// at System.Threading.Tasks.Task`1.InnerInvoke() +// at System.Threading.Tasks.Task.<>c.<.cctor>b__277_0(Object obj) +// at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) +// --- End of stack trace from previous location --- +// at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) +// at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) +// --- End of inner exception stack trace --- +// at System.AggregateException.Handle(Func`2 predicate) +// at .$Exception1.main@() +// diff --git a/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fsproj b/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fsproj new file mode 100644 index 00000000000..489dceab6c8 --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fsproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + + + + + + diff --git a/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/flatten2.fs b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/flatten2.fs new file mode 100644 index 00000000000..394e25abd32 --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/flatten2.fs @@ -0,0 +1,38 @@ +module flatten2 +// +open System +open System.Threading.Tasks + +type CustomException(message) = + inherit Exception(message) + +let task1 = + Task.Factory.StartNew (fun () -> + let child1 = + Task.Factory.StartNew( + (fun () -> + let child2 = + Task.Factory.StartNew( + (fun () -> raise (CustomException "Attached child2 faulted,")), + TaskCreationOptions.AttachedToParent + ) + raise (CustomException "Attached child1 faulted.")), + TaskCreationOptions.AttachedToParent + ) + () + ) + +try + task1.Wait() +with +| :? AggregateException as ae -> + for e in ae.Flatten().InnerExceptions do + if e :? CustomException then + printfn "%s" e.Message + else + reraise() + +// The example displays the following output: +// Attached child1 faulted. +// Attached child2 faulted. +// diff --git a/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/handlemethod2.fs b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/handlemethod2.fs new file mode 100644 index 00000000000..c879e554195 --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/handlemethod2.fs @@ -0,0 +1,26 @@ +module handlemethod2 +// +open System +open System.Threading.Tasks + +type CustomException(message) = + inherit Exception(message) + +let task1 = + Task.Run(fun () -> raise (CustomException "This exception is expected!")) + +try + task1.Wait() +with +| :? AggregateException as ae -> + // Call the Handle method to handle the custom exception, + // otherwise rethrow the exception. + ae.Handle (fun ex -> + if ex :? CustomException then + printfn $"{ex.Message}" + + ex :? CustomException) + +// The example displays the following output: +// This exception is expected! +// diff --git a/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions.fs b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions.fs new file mode 100644 index 00000000000..b69a636c397 --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions.fs @@ -0,0 +1,53 @@ +module taskexceptions +// +open System +open System.IO +open System.Threading.Tasks + +let getAllFiles path = + let task1 = + Task.Run(fun () -> Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories)) + + try + task1.Result + with + | :? AggregateException as ae -> + ae.Handle (fun x -> + // Handle an UnauthorizedAccessException + if x :? UnauthorizedAccessException then + printfn "You do not have permission to access all folders in this path." + printfn "See your network administrator or try another path." + + x :? UnauthorizedAccessException) + + Array.empty + +// This should throw an UnauthorizedAccessException. +try + let files = getAllFiles @"C:\" + + if not (isNull files) then + for file in files do + printfn $"{file}" +with +| :? AggregateException as ae -> + for ex in ae.InnerExceptions do + printfn $"{ex.GetType().Name}: {ex.Message}" + +printfn "" + +// This should throw an ArgumentException. +try + for s in getAllFiles "" do + printfn $"{s}" +with +| :? AggregateException as ae -> + for ex in ae.InnerExceptions do + printfn $"{ex.GetType().Name}: {ex.Message}" + +// The example displays the following output: +// You do not have permission to access all folders in this path. +// See your network administrator or try another path. +// +// ArgumentException: The path is empty. (Parameter 'path') +// diff --git a/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions2.fs b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions2.fs new file mode 100644 index 00000000000..92d8034a6d7 --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions2.fs @@ -0,0 +1,43 @@ +module taskexceptions2 +// +open System +open System.IO +open System.Threading.Tasks + +let executeTasks () = + // Assume this is a user-entered String. + let path = @"C:\" + + let tasks = + [| Task.Run (fun () -> + // This should throw an UnauthorizedAccessException. + Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories)) + :> Task + Task.Run (fun () -> + if path = @"C:\" then + raise (ArgumentException "The system root is not a valid path.") + + [| ".txt"; ".dll"; ".exe"; ".bin"; ".dat" |]) + :> Task + Task.Run(fun () -> raise (NotImplementedException "This operation has not been implemented")) |] + + try + Task.WaitAll(tasks) + with + | :? AggregateException as ae -> raise (ae.Flatten()) + +try + executeTasks () +with +| :? AggregateException as ae -> + for e in ae.InnerExceptions do + printfn $"{e.GetType().Name}:\n {e.Message}" + +// The example displays the following output: +// UnauthorizedAccessException: +// Access to the path 'C:\Documents and Settings' is denied. +// ArgumentException: +// The system root is not a valid path. +// NotImplementedException: +// This operation has not been implemented. +// diff --git a/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/tpl_exceptions.fsproj b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/tpl_exceptions.fsproj new file mode 100644 index 00000000000..01c77cf1e9a --- /dev/null +++ b/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/tpl_exceptions.fsproj @@ -0,0 +1,15 @@ + + + + Exe + net5.0 + + + + + + + + + + diff --git a/xml/System/AggregateException.xml b/xml/System/AggregateException.xml index f0de8893cbe..21895053bef 100644 --- a/xml/System/AggregateException.xml +++ b/xml/System/AggregateException.xml @@ -71,6 +71,7 @@ The following example catches the exception and calls the method to handle each exception it contains. Compiling and running the example with the first `task1` variable should result in an object that contains an exception. Commenting out that line, uncommenting the second `task1` variable, and compiling and running the example produces an object that contains an exception. :::code language="csharp" source="~/samples/snippets/csharp/VS_Snippets_CLR_System/system.aggregateexception.class/cs/exception1.cs" id="Snippet1"::: + :::code language="fsharp" source="~/samples/snippets/fsharp/VS_Snippets_CLR_System/system.aggregateexception.class/fs/exception1.fs" id="Snippet1"::: :::code language="vb" source="~/samples/snippets/visualbasic/VS_Snippets_CLR_System/system.aggregateexception.class/vb/exception1.vb" id="Snippet1"::: ]]> @@ -548,11 +549,13 @@ In the following example, nested instances are flattened and handled in just one loop. :::code language="csharp" source="~/samples/snippets/csharp/VS_Snippets_Misc/tpl_exceptions/cs/flatten2.cs" id="Snippet22"::: + :::code language="fsharp" source="~/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/flatten2.fs" id="Snippet22"::: :::code language="vb" source="~/samples/snippets/visualbasic/VS_Snippets_Misc/tpl_exceptions/vb/flatten2.vb" id="Snippet22"::: You can also use the method to rethrow the inner exceptions from multiple instances thrown by multiple tasks in a single instance, as the following example shows. :::code language="csharp" source="~/samples/snippets/csharp/VS_Snippets_Misc/tpl_exceptions/cs/taskexceptions2.cs" id="Snippet13"::: + :::code language="fsharp" source="~/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions2.fs" id="Snippet13"::: :::code language="vb" source="~/samples/snippets/visualbasic/VS_Snippets_Misc/tpl_exceptions/vb/taskexceptions2.vb" id="Snippet13"::: ]]> @@ -712,11 +715,13 @@ Ordinarily, an exception handler that catches an exception uses a `foreach` loop (in C#) or `For Each` loop (in Visual Basic) to handle each exception in its collection. Instead, the following example uses the method to handle each exception, and only re-throws exceptions that are not `CustomException` instances. :::code language="csharp" source="~/samples/snippets/csharp/VS_Snippets_Misc/tpl_exceptions/cs/handlemethod2.cs" id="Snippet16"::: + :::code language="fsharp" source="~/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/handlemethod2.fs" id="Snippet16"::: :::code language="vb" source="~/samples/snippets/visualbasic/VS_Snippets_Misc/tpl_exceptions/vb/handlemethod2.vb" id="Snippet16"::: The following is a more complete example that uses the method to provide special handling for an when enumerating files. :::code language="csharp" source="~/samples/snippets/csharp/VS_Snippets_Misc/tpl_exceptions/cs/taskexceptions.cs" id="Snippet12"::: + :::code language="fsharp" source="~/samples/snippets/fsharp/VS_Snippets_Misc/tpl_exceptions/fs/taskexceptions.fs" id="Snippet12"::: :::code language="vb" source="~/samples/snippets/visualbasic/VS_Snippets_Misc/tpl_exceptions/vb/taskexceptions.vb" id="Snippet12"::: ]]>