From 5d348bea0939442814a02c709206d036838945a8 Mon Sep 17 00:00:00 2001 From: Marcus Winding Quistgaard Date: Sun, 7 Jun 2020 13:44:57 +0200 Subject: [PATCH] Add top-level exception handler, unwrap AggregateException. Closes #6 Sometimes WebExceptions seem to be thrown as-is, while other times they are wrapped in an AggregateException. Not entirely sure why, but now we catch wrapped WebExceptions as well. Additionally, with a new top-level exception handler the program shouldn't outright crash anymore if an unhandled error occurs. Instead it provides a pop-up that lets the user retrieve the error-message and stacktrace that can then be included in a github issue. --- src/DataAccess/Helpers/ImageHelper.cs | 2 +- .../Properties/Settings.Designer.cs | 8 +++--- src/DataAccess/Properties/Settings.settings | 6 ++--- src/DataAccess/app.config | 6 ++--- src/Logic/Handlers/ImgurHandler.cs | 11 ++++++++ src/Logic/Handlers/RedditHandler.cs | 14 +++++++++- src/UI/ViewModels/ImgurControlViewModel.cs | 26 ++++++++++++++++--- src/UI/ViewModels/LocalControlViewModel.cs | 22 +++++++++++++++- src/UI/ViewModels/RedditControlViewModel.cs | 24 +++++++++++++++-- 9 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/DataAccess/Helpers/ImageHelper.cs b/src/DataAccess/Helpers/ImageHelper.cs index 86b108c..61d6164 100644 --- a/src/DataAccess/Helpers/ImageHelper.cs +++ b/src/DataAccess/Helpers/ImageHelper.cs @@ -39,7 +39,7 @@ public static async Task GetWebContent(string url) } catch (TaskCanceledException e) { - throw new WebException("Connection lost", e); + throw new WebException("Connection lost.", e); } } diff --git a/src/DataAccess/Properties/Settings.Designer.cs b/src/DataAccess/Properties/Settings.Designer.cs index cd48128..1b493fc 100644 --- a/src/DataAccess/Properties/Settings.Designer.cs +++ b/src/DataAccess/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace DataAccess.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -82,7 +82,7 @@ public int FallbackDimensionHeight { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("PC:ImageDownloader:v1.2.0 (by /u/Jameak)")] + [global::System.Configuration.DefaultSettingValueAttribute("PC:ImageDownloader:v1.2.1 (by /u/Jameak)")] public string RedditUserAgent { get { return ((string)(this["RedditUserAgent"])); @@ -91,7 +91,7 @@ public string RedditUserAgent { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("PC:ImageDownloader:v1.2.0 (github.com/jameak/ImageDownloader)")] + [global::System.Configuration.DefaultSettingValueAttribute("PC:ImageDownloader:v1.2.1 (github.com/jameak/ImageDownloader)")] public string DeviantartUserAgent { get { return ((string)(this["DeviantartUserAgent"])); @@ -130,7 +130,7 @@ public string ImgurClientIDDefault { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("v1.2.0")] + [global::System.Configuration.DefaultSettingValueAttribute("v1.2.1")] public string VersionNumber { get { return ((string)(this["VersionNumber"])); diff --git a/src/DataAccess/Properties/Settings.settings b/src/DataAccess/Properties/Settings.settings index 6e02c05..237acac 100644 --- a/src/DataAccess/Properties/Settings.settings +++ b/src/DataAccess/Properties/Settings.settings @@ -24,10 +24,10 @@ 0 - PC:ImageDownloader:v1.2.0 (by /u/Jameak) + PC:ImageDownloader:v1.2.1 (by /u/Jameak) - PC:ImageDownloader:v1.2.0 (github.com/jameak/ImageDownloader) + PC:ImageDownloader:v1.2.1 (github.com/jameak/ImageDownloader) J687G-r-0ZTQsg @@ -39,7 +39,7 @@ 0fed969f9f62557 - v1.2.0 + v1.2.1 ImageDownloader diff --git a/src/DataAccess/app.config b/src/DataAccess/app.config index 73b0d61..60c1b65 100644 --- a/src/DataAccess/app.config +++ b/src/DataAccess/app.config @@ -41,10 +41,10 @@ - PC:ImageDownloader:v1.2.0 (by /u/Jameak) + PC:ImageDownloader:v1.2.1 (by /u/Jameak) - PC:ImageDownloader:v1.2.0 (github.com/jameak/ImageDownloader) + PC:ImageDownloader:v1.2.1 (github.com/jameak/ImageDownloader) J687G-r-0ZTQsg @@ -53,7 +53,7 @@ 0fed969f9f62557 - v1.2.0 + v1.2.1 ImageDownloader diff --git a/src/Logic/Handlers/ImgurHandler.cs b/src/Logic/Handlers/ImgurHandler.cs index 56bbf85..8663f70 100644 --- a/src/Logic/Handlers/ImgurHandler.cs +++ b/src/Logic/Handlers/ImgurHandler.cs @@ -104,6 +104,17 @@ await Task.Run(() => { WriteToLog(sync, outputLog, $"IO Failure - Error occured while saving image: {imageName}"); } + catch (AggregateException ex) + { + if (ex.InnerException is WebException) + { + WriteToLog(sync, outputLog, $"Unable to download image: {imageName}"); + } + else + { + WriteToLog(sync, outputLog, $"Unknown error occured for {imageName}. Error message is: " + ex.InnerException.Message); + } + } } }); } diff --git a/src/Logic/Handlers/RedditHandler.cs b/src/Logic/Handlers/RedditHandler.cs index 4951906..cac5eba 100644 --- a/src/Logic/Handlers/RedditHandler.cs +++ b/src/Logic/Handlers/RedditHandler.cs @@ -109,7 +109,19 @@ await Task.Run(() => } catch (IOException) { - WriteToLog(sync, outputLog, $"IO Failure - Error occured while saving image: {imageName}"); + WriteToLog(sync, outputLog, + $"IO Failure - Error occured while saving image: {imageName}"); + } + catch (AggregateException ex) + { + if (ex.InnerException is WebException) + { + WriteToLog(sync, outputLog, $"Unable to download image: {imageName}"); + } + else + { + WriteToLog(sync, outputLog, $"Unknown error occured for {imageName}. Error message is: " + ex.InnerException.Message); + } } } }); diff --git a/src/UI/ViewModels/ImgurControlViewModel.cs b/src/UI/ViewModels/ImgurControlViewModel.cs index f77cc43..78f22d5 100644 --- a/src/UI/ViewModels/ImgurControlViewModel.cs +++ b/src/UI/ViewModels/ImgurControlViewModel.cs @@ -54,9 +54,29 @@ public override async void StartDownload() else { ProgressMaxValue = content.GetImages().Count(); - await - _downloader.FetchContent(content, TargetFolder, ResolutionFilter, - Log = new ThreadsafeObservableStringCollection()); + try + { + await + _downloader.FetchContent(content, TargetFolder, ResolutionFilter, + Log = new ThreadsafeObservableStringCollection()); + } + catch (Exception e) + { + Log.Add("Unhandled error occurred during downloading. Aborting."); + var message = "Unhandled error occurred during download.\n" + + "Downloading has been aborted.\n\n" + + "To get the the error-message and stacktrace\n" + + "copied to your clipboard, click 'OK'.\n" + + "If you want to report this error, please provide\n" + + "the error message in an issue on\n" + + "Github.com/Jameak/ImageDownloader"; + var result = MessageBox.Show(message, "ImageDownloader", MessageBoxButton.OKCancel); + if (result == MessageBoxResult.OK) + { + Clipboard.SetText(e.ToString()); + MessageBox.Show("Error message copied to clipboard", "ImageDownloader", MessageBoxButton.OK); + } + } } IsIdle = true; diff --git a/src/UI/ViewModels/LocalControlViewModel.cs b/src/UI/ViewModels/LocalControlViewModel.cs index 3e813ee..837983b 100644 --- a/src/UI/ViewModels/LocalControlViewModel.cs +++ b/src/UI/ViewModels/LocalControlViewModel.cs @@ -52,7 +52,27 @@ public override async void StartDownload() else { ProgressMaxValue = content.GetImages().Count(); - await _downloader.FetchContent(content, TargetFolder, ResolutionFilter, Log, PreserveFolderHierarchy); + try + { + await _downloader.FetchContent(content, TargetFolder, ResolutionFilter, Log, PreserveFolderHierarchy); + } + catch (Exception e) + { + Log.Add("Unhandled error occurred during operation. Aborting."); + var message = "Unhandled error occurred during operation.\n" + + "Operation has been aborted.\n\n" + + "To get the the error-message and stacktrace\n" + + "copied to your clipboard, click 'OK'.\n" + + "If you want to report this error, please provide\n" + + "the error message in an issue on\n" + + "Github.com/Jameak/ImageDownloader"; + var result = MessageBox.Show(message, "ImageDownloader", MessageBoxButton.OKCancel); + if (result == MessageBoxResult.OK) + { + Clipboard.SetText(e.ToString()); + MessageBox.Show("Exception text copied to clipboard", "ImageDownloader", MessageBoxButton.OK); + } + } } IsIdle = true; diff --git a/src/UI/ViewModels/RedditControlViewModel.cs b/src/UI/ViewModels/RedditControlViewModel.cs index 8e34cc8..e66aadc 100644 --- a/src/UI/ViewModels/RedditControlViewModel.cs +++ b/src/UI/ViewModels/RedditControlViewModel.cs @@ -91,8 +91,28 @@ public override async void StartDownload() else { ProgressMaxValue = content.GetImages().Count(); - await - _downloader.FetchContent(content, TargetFolder, Filter, Log, SaveAlbumInNestedFolder); + try + { + await + _downloader.FetchContent(content, TargetFolder, Filter, Log, SaveAlbumInNestedFolder); + } + catch (Exception e) + { + Log.Add("Unhandled error occurred during downloading. Aborting."); + var message = "Unhandled error occurred during download.\n" + + "Downloading has been aborted.\n\n" + + "To get the the error-message and stacktrace\n" + + "copied to your clipboard, click 'OK'.\n" + + "If you want to report this error, please provide\n" + + "the error message in an issue on\n" + + "Github.com/Jameak/ImageDownloader"; + var result = MessageBox.Show(message, "ImageDownloader", MessageBoxButton.OKCancel); + if (result == MessageBoxResult.OK) + { + Clipboard.SetText(e.ToString()); + MessageBox.Show("Exception text copied to clipboard", "ImageDownloader", MessageBoxButton.OK); + } + } } IsIdle = true;