From 8fcf59aaae481e805feb7dfd14c1fc0a1c2b93ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuzhan=20Koral?= <45078678+oguzhankoral@users.noreply.github.com> Date: Fri, 24 May 2024 22:17:37 +0300 Subject: [PATCH] CNX-9303 define a top level error handling strategy for all connectors most likely in the i bridge (#3439) * Catch TargetInvocationException on bridge * Catch AggregateException for async calls * Extract ReportUnhandledError method * Be more specific on binding methods and catch unhandled expections on the bridge * Remove unused namespaces * SpeckleSendFilterException inherit from SpeckleException * Simplify general error handling on bridge * Simplify error message --- .../Bindings/ArcGISReceiveBinding.cs | 14 +++++---- .../Bindings/ArcGISSendBinding.cs | 30 ++++++++++++------- .../Operations/Send/RootObjectBuilder.cs | 6 ---- .../Bindings/AutocadReceiveBinding.cs | 14 +++++---- .../Bindings/AutocadSendBinding.cs | 21 ++++++++----- .../Bindings/SendBinding.cs | 25 +++++++++++----- .../Operations/Send/RevitRootObjectBuilder.cs | 3 +- .../Bindings/RhinoReceiveBinding.cs | 14 +++++---- .../Bindings/RhinoSendBinding.cs | 26 ++++++++++------ .../Operations/Send/RhinoRootObjectBuilder.cs | 13 +------- .../Bridge/BrowserBridge.cs | 18 ++++++++++- .../Exceptions/SpeckleSendFilterException.cs | 14 +++++++++ 12 files changed, 125 insertions(+), 73 deletions(-) create mode 100644 DUI3-DX/DUI3/Speckle.Connectors.DUI/Exceptions/SpeckleSendFilterException.cs diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs index 58d2e9e462..f39adfc67d 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISReceiveBinding.cs @@ -6,7 +6,6 @@ using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Cancellation; using Speckle.Connectors.Utils.Operations; -using Speckle.Core.Logging; using ICancelable = System.Reactive.Disposables.ICancelable; namespace Speckle.Connectors.ArcGIS.Bindings; @@ -39,15 +38,16 @@ public async Task Receive(string modelCardId) { try { - // Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); - // Get receiver card if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No download model card was found."); } + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); + using IUnitOfWork unitOfWork = _unitOfWorkFactory.Resolve(); // Receive host objects @@ -65,9 +65,11 @@ public async Task Receive(string modelCardId) Commands.SetModelReceiveResult(modelCardId, receivedObjectIds.ToList()); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + // Catch here specific exceptions if they related to model card. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + // SWALLOW -> UI handles it immediately, so we do not need to handle anything + return; } } diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 5227145454..9f883384c3 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -3,19 +3,19 @@ using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.Utils.Cancellation; -using Speckle.Core.Logging; using ICancelable = System.Reactive.Disposables.ICancelable; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.DUI.Settings; -using Speckle.Connectors.Utils; using ArcGIS.Desktop.Mapping.Events; using ArcGIS.Desktop.Mapping; using Speckle.Connectors.ArcGIS.Filters; using ArcGIS.Desktop.Editing.Events; using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Core.Data; +using Speckle.Connectors.DUI.Exceptions; +using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models; @@ -258,15 +258,15 @@ public async Task Send(string modelCardId) using IUnitOfWork> unitOfWork = _unitOfWorkFactory.Resolve>(); try { - // 0 - Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); - - // 1 - Get model if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No publish model card was found."); } + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); + var sendInfo = new SendInfo( modelCard.AccountId.NotNull(), modelCard.ProjectId.NotNull(), @@ -286,6 +286,14 @@ public async Task Send(string modelCardId) .Where(obj => obj != null) .ToList(); + if (!mapMembers.Any()) + { + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException( + "No objects were found to convert. Please update your publish filter!" + ); + } + var result = await unitOfWork.Service .Execute( mapMembers, @@ -310,13 +318,15 @@ public async Task Send(string modelCardId) Commands.SetModelCreatedVersionId(modelCardId, sendResult.rootObjId); } - catch (OperationCanceledException) + // Catch here specific exceptions if they related to model card. + catch (SpeckleSendFilterException e) { - return; + Commands.SetModelError(modelCardId, e); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + // SWALLOW -> UI handles it immediately, so we do not need to handle anything + return; } } diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/RootObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/RootObjectBuilder.cs index 637d39bbae..6af77c66cb 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/RootObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/RootObjectBuilder.cs @@ -26,12 +26,6 @@ public Base Build( CancellationToken ct = default ) { - if (!objects.Any()) - { - // POC: not sure if we would want to throw in here? - throw new InvalidOperationException("No objects were found. Please update your send filter!"); - } - // POC: does this feel like the right place? I am wondering if this should be called from within send/rcv? // begin the unit of work using var uow = _unitOfWorkFactory.Resolve(); diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs index 181e152051..7cce92087a 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadReceiveBinding.cs @@ -6,7 +6,6 @@ using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Operations; -using Speckle.Core.Logging; using ICancelable = System.Reactive.Disposables.ICancelable; namespace Speckle.Connectors.Autocad.Bindings; @@ -43,15 +42,16 @@ public async Task Receive(string modelCardId) using var unitOfWork = _unitOfWorkFactory.Resolve(); try { - // Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); - // Get receiver card if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No download model card was found."); } + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); + // Receive host objects IEnumerable receivedObjectIds = await unitOfWork.Service .Execute( @@ -67,9 +67,11 @@ public async Task Receive(string modelCardId) Commands.SetModelReceiveResult(modelCardId, receivedObjectIds.ToList()); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + // Catch here specific exceptions if they related to model card. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + // SWALLOW -> UI handles it immediately, so we do not need to handle anything + return; } } diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index d33db5b048..2549d7744a 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -6,9 +6,9 @@ using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.Utils.Cancellation; -using Speckle.Core.Logging; using Speckle.Autofac.DependencyInjection; using Speckle.Connectors.Autocad.Operations.Send; +using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models; using ICancelable = System.Reactive.Disposables.ICancelable; @@ -122,23 +122,26 @@ private async Task SendInternal(string modelCardId) { try { - using var uow = _unitOfWorkFactory.Resolve>(); - // 0 - Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); - - // 1 - Get model if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No publish model card was found."); } + using var uow = _unitOfWorkFactory.Resolve>(); + + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); + // Get elements to convert List autocadObjects = Application.DocumentManager.CurrentDocument.GetObjects( modelCard.SendFilter.NotNull().GetObjectIds() ); + if (autocadObjects.Count == 0) { - throw new InvalidOperationException("No objects were found. Please update your send filter!"); + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); } var sendInfo = new SendInfo( @@ -170,11 +173,13 @@ private async Task SendInternal(string modelCardId) Commands.SetModelCreatedVersionId(modelCardId, sendResult.rootObjId); } + // Catch here specific exceptions if they related to model card. catch (OperationCanceledException) { + // SWALLOW -> UI handles it immediately, so we do not need to handle anything return; } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + catch (SpeckleSendFilterException e) { Commands.SetModelError(modelCardId, e); } diff --git a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SendBinding.cs b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SendBinding.cs index d8eac56d4e..0383e8a77c 100644 --- a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SendBinding.cs +++ b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/SendBinding.cs @@ -9,6 +9,7 @@ using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.DUI.Bindings; using Speckle.Autofac.DependencyInjection; +using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Models; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models; @@ -72,10 +73,6 @@ public void CancelSend(string modelCardId) private async Task HandleSend(string modelCardId) { - // POC: probably the CTS SHOULD be injected as InstancePerLifetimeScope and then - // it can be injected where needed instead of passing it around like a bomb :D - CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId); - // POC: this try catch pattern is coming from Rhino. I see there is a semi implemented "SpeckleTopLevelExceptionHandler" // above that wraps the call of this HandleSend, but it currently is not doing anything - resulting in all errors from here // bubbling up to the bridge. @@ -83,9 +80,14 @@ private async Task HandleSend(string modelCardId) { if (Store.GetModelById(modelCardId) is not SenderModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No publish model card was found."); } + // POC: probably the CTS SHOULD be injected as InstancePerLifetimeScope and then + // it can be injected where needed instead of passing it around like a bomb :D + CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId); + using IUnitOfWork> sendOperation = _unitOfWorkFactory.Resolve< SendOperation >(); @@ -96,6 +98,12 @@ private async Task HandleSend(string modelCardId) .Select(id => ElementId.Parse(id)) .ToList(); + if (!revitObjects.Any()) + { + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); + } + var sendInfo = new SendInfo( modelCard.AccountId.NotNull(), modelCard.ProjectId.NotNull(), @@ -125,13 +133,14 @@ private async Task HandleSend(string modelCardId) Commands.SetModelCreatedVersionId(modelCardId, sendResult.rootObjId); } - catch (OperationCanceledException) + // Catch here specific exceptions if they related to model card. + catch (SpeckleSendFilterException e) { - return; + Commands.SetModelError(modelCardId, e); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + return; } } diff --git a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 2f7f484807..921d443444 100644 --- a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -1,6 +1,7 @@ using Speckle.Converters.Common; using Speckle.Core.Models; using Autodesk.Revit.DB; +using Speckle.Connectors.DUI.Exceptions; using Speckle.Converters.RevitShared.Helpers; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Operations; @@ -56,7 +57,7 @@ public Base Build( if (revitElements.Count == 0) { - throw new InvalidOperationException("No objects were found. Please update your send filter!"); + throw new SpeckleSendFilterException("No objects were found. Please update your send filter!"); } var countProgress = 0; // because for(int i = 0; ...) loops are so last year diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs index 62071b8b54..2373bc69ad 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs @@ -6,7 +6,6 @@ using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Cancellation; using Speckle.Connectors.Utils.Operations; -using Speckle.Core.Logging; namespace Speckle.Connectors.Rhino7.Bindings; @@ -41,15 +40,16 @@ public async Task Receive(string modelCardId) using var unitOfWork = _unitOfWorkFactory.Resolve(); try { - // Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId); - // Get receiver card if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No download model card was found."); } + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId); + // Receive host objects IEnumerable receivedObjectIds = await unitOfWork.Service .Execute( @@ -66,9 +66,11 @@ public async Task Receive(string modelCardId) // POC: Here we can't set receive result if ReceiveOperation throws an error. Commands.SetModelReceiveResult(modelCardId, receivedObjectIds.ToList()); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + // Catch here specific exceptions if they related to model card. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + // SWALLOW -> UI handles it immediately, so we do not need to handle anything + return; } } diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs index 25e3631635..76bca9085c 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs @@ -6,10 +6,10 @@ using Speckle.Connectors.DUI.Models.Card; using Speckle.Connectors.Rhino7.HostApp; using Speckle.Connectors.Utils.Cancellation; -using Speckle.Core.Logging; using ICancelable = System.Reactive.Disposables.ICancelable; using Speckle.Autofac.DependencyInjection; using Rhino.DocObjects; +using Speckle.Connectors.DUI.Exceptions; using Speckle.Connectors.DUI.Models.Card.SendFilter; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models; @@ -137,15 +137,15 @@ public async Task Send(string modelCardId) using var unitOfWork = _unitOfWorkFactory.Resolve>(); try { - // 0 - Init cancellation token source -> Manager also cancel it if exist before - CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); - - // 1 - Get model if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard) { + // Handle as GLOBAL ERROR at BrowserBridge throw new InvalidOperationException("No publish model card was found."); } + // Init cancellation token source -> Manager also cancel it if exist before + CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId); + List rhinoObjects = modelCard.SendFilter .NotNull() .GetObjectIds() @@ -153,6 +153,12 @@ public async Task Send(string modelCardId) .Where(obj => obj != null) .ToList(); + if (!rhinoObjects.Any()) + { + // Handle as CARD ERROR in this function + throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!"); + } + var sendInfo = new SendInfo( modelCard.AccountId.NotNull(), modelCard.ProjectId.NotNull(), @@ -182,13 +188,15 @@ public async Task Send(string modelCardId) Commands.SetModelCreatedVersionId(modelCardId, sendResult.rootObjId); } - catch (OperationCanceledException) + // Catch here specific exceptions if they related to model card. + catch (SpeckleSendFilterException e) { - return; + Commands.SetModelError(modelCardId, e); } - catch (Exception e) when (!e.IsFatal()) // All exceptions should be handled here if possible, otherwise we enter "crashing the host app" territory. + catch (OperationCanceledException) { - Commands.SetModelError(modelCardId, e); + // SWALLOW -> UI handles it immediately, so we do not need to handle anything + return; } } diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs index e599829eaa..5f1020556c 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs @@ -26,18 +26,7 @@ public Base Build( SendInfo sendInfo, Action? onOperationProgressed = null, CancellationToken ct = default - ) - { - if (!objects.Any()) - { - // POC: not sure if we would want to throw in here? - throw new InvalidOperationException("No objects were found. Please update your send filter!"); - } - - Base commitObject = ConvertObjects(objects, sendInfo, onOperationProgressed, ct); - - return commitObject; - } + ) => ConvertObjects(objects, sendInfo, onOperationProgressed, ct); private Collection ConvertObjects( IReadOnlyList rhinoObjects, diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs index 564f587ccf..5050f652e3 100644 --- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs @@ -207,6 +207,7 @@ private void ExecuteMethod(string methodName, string requestId, string args) { continue; } + typedArgs[i] = ccc; } @@ -223,7 +224,7 @@ private void ExecuteMethod(string methodName, string requestId, string args) else // It's an async call { // See note at start of function. Do not asyncify! - resultTypedTask.Wait(); + resultTypedTask.GetAwaiter().GetResult(); // If has a "Result" property return the value otherwise null (Task etc) PropertyInfo resultProperty = resultTypedTask.GetType().GetProperty("Result"); @@ -243,6 +244,21 @@ private void ExecuteMethod(string methodName, string requestId, string args) NotifyUIMethodCallResultReady(requestId, serializedError); } + catch (Exception e) when (!e.IsFatal()) + { + ReportUnhandledError(requestId, e); + } + } + + /// + /// Errors that not handled on bindings. + /// + private void ReportUnhandledError(string requestId, Exception e) + { + var errorDetails = new { e.Message, Error = e.ToString() }; + + var serializedError = JsonConvert.SerializeObject(errorDetails, _serializerOptions); + NotifyUIMethodCallResultReady(requestId, serializedError); } /// diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Exceptions/SpeckleSendFilterException.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Exceptions/SpeckleSendFilterException.cs new file mode 100644 index 0000000000..f5ef115b07 --- /dev/null +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Exceptions/SpeckleSendFilterException.cs @@ -0,0 +1,14 @@ +using Speckle.Core.Logging; + +namespace Speckle.Connectors.DUI.Exceptions; + +public class SpeckleSendFilterException : SpeckleException +{ + public SpeckleSendFilterException() { } + + public SpeckleSendFilterException(string message) + : base(message) { } + + public SpeckleSendFilterException(string message, Exception innerException) + : base(message, innerException) { } +}