From 6d8f3d5ae2d18a3cf88007707b0893beaa5e6b2f Mon Sep 17 00:00:00 2001
From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
Date: Fri, 14 Jun 2024 14:22:03 +0100
Subject: [PATCH 01/17] Wip changes
---
Core/Core/Core.csproj | 1 -
.../Bindings/ArcGISSelectionBinding.cs | 12 +-
.../DUI3ControlWebView.xaml.cs | 12 +-
.../Bindings/IBasicConnectorBinding.cs | 2 +-
.../Bridge/BrowserBridge.cs | 146 ++++++++++--------
.../Speckle.Connectors.DUI/Bridge/IBridge.cs | 5 +
.../Bridge/TopLevelExceptionHandler.cs | 99 ++++++++++++
.../ContainerRegistration.cs | 2 +-
.../ContainerRegistration.cs | 7 +-
9 files changed, 206 insertions(+), 80 deletions(-)
create mode 100644 DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/TopLevelExceptionHandler.cs
diff --git a/Core/Core/Core.csproj b/Core/Core/Core.csproj
index 275dcc12cc..caaa2ab93a 100644
--- a/Core/Core/Core.csproj
+++ b/Core/Core/Core.csproj
@@ -51,7 +51,6 @@
-
diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs
index ddc096b629..a4d08c7e8d 100644
--- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs
+++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs
@@ -7,22 +7,22 @@ namespace Speckle.Connectors.ArcGIS.Bindings;
public class ArcGISSelectionBinding : ISelectionBinding
{
- public string Name { get; } = "selectionBinding";
- public IBridge Parent { get; set; }
+ public string Name => "selectionBinding";
+ public IBridge Parent { get; }
- public ArcGISSelectionBinding(IBridge parent)
+ public ArcGISSelectionBinding(IBridge parent, TopLevelExceptionHandler topLevelHandler)
{
Parent = parent;
// example: https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Map-Authoring/QueryBuilderControl/DefinitionQueryDockPaneViewModel.cs
// MapViewEventArgs args = new(MapView.Active);
- TOCSelectionChangedEvent.Subscribe(OnSelectionChanged, true);
+ TOCSelectionChangedEvent.Subscribe(_ => topLevelHandler.CatchUnhandled(OnSelectionChanged), true);
}
- private void OnSelectionChanged(MapViewEventArgs args)
+ private void OnSelectionChanged()
{
SelectionInfo selInfo = GetSelection();
- Parent?.Send(SelectionBindingEvents.SET_SELECTION, selInfo);
+ Parent.Send(SelectionBindingEvents.SET_SELECTION, selInfo);
}
public SelectionInfo GetSelection()
diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs
index 4e9cc6bcc5..00cb93993f 100644
--- a/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs
+++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/DUI3ControlWebView.xaml.cs
@@ -2,18 +2,22 @@
using System.Windows.Threading;
using Microsoft.Web.WebView2.Core;
using Speckle.Connectors.DUI.Bindings;
+using Speckle.Connectors.DUI.Bridge;
namespace Speckle.Connectors.DUI.WebView;
public sealed partial class DUI3ControlWebView : UserControl
{
private readonly IEnumerable> _bindings;
+ private readonly TopLevelExceptionHandler _topLevelExceptionHandler;
- public DUI3ControlWebView(IEnumerable> bindings)
+ public DUI3ControlWebView(IEnumerable> bindings, TopLevelExceptionHandler topLevelExceptionHandler)
{
_bindings = bindings;
+ _topLevelExceptionHandler = topLevelExceptionHandler;
InitializeComponent();
- Browser.CoreWebView2InitializationCompleted += OnInitialized;
+ Browser.CoreWebView2InitializationCompleted += (sender, args) =>
+ _topLevelExceptionHandler.CatchUnhandled(() => OnInitialized(sender, args));
}
private void ShowDevToolsMethod() => Browser.CoreWebView2.OpenDevToolsWindow();
@@ -30,9 +34,9 @@ private void ExecuteScriptAsyncMethod(string script)
private void OnInitialized(object? sender, CoreWebView2InitializationCompletedEventArgs e)
{
- if (e.IsSuccess == false)
+ if (!e.IsSuccess)
{
- //POC: avoid silently accepting webview failures handle...
+ throw new InvalidOperationException("Webview Failed to initialize", e.InitializationException);
}
// We use Lazy here to delay creating the binding until after the Browser is fully initialized.
diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs
index 966be49fe2..7b38ee9fbd 100644
--- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs
+++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/IBasicConnectorBinding.cs
@@ -45,7 +45,7 @@ public class BasicConnectorBindingCommands
private const string NOTIFY_DOCUMENT_CHANGED_EVENT_NAME = "documentChanged";
private const string SET_MODEL_PROGRESS_UI_COMMAND_NAME = "setModelProgress";
private const string SET_MODEL_ERROR_UI_COMMAND_NAME = "setModelError";
- private const string SET_GLOBAL_NOTIFICATION = "setGlobalNotification";
+ internal const string SET_GLOBAL_NOTIFICATION = "setGlobalNotification";
protected IBridge Bridge { get; }
diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs
index 2c27fccc38..026acec6a8 100644
--- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs
+++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bridge/BrowserBridge.cs
@@ -28,6 +28,7 @@ public class BrowserBridge : IBridge
private readonly JsonSerializerSettings _serializerOptions;
private readonly Dictionary _resultsStore = new();
private readonly SynchronizationContext _mainThreadContext;
+ private readonly TopLevelExceptionHandler _topLevelExceptionHandler;
private Dictionary BindingMethodCache { get; set; } = new();
private ActionBlock? _actionBlock;
@@ -77,7 +78,7 @@ public BrowserBridge(JsonSerializerSettings jsonSerializerSettings, ILoggerFacto
{
_serializerOptions = jsonSerializerSettings;
_logger = loggerFactory.CreateLogger();
-
+ _topLevelExceptionHandler = new(_logger); //TODO: Probably we could inject this with a Lazy somewhere
// Capture the main thread's SynchronizationContext
_mainThreadContext = SynchronizationContext.Current;
}
@@ -108,19 +109,31 @@ Action showDevToolsAction
// Whenever the ui will call run method inside .net, it will post a message to this action block.
// This conveniently executes the code outside the UI thread and does not block during long operations (such as sending).
- // POC: I wonder if TL exception handler should be living here...
_actionBlock = new ActionBlock(
- args => ExecuteMethod(args.MethodName, args.RequestId, args.MethodArgs),
+ OnActionBlock,
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 1000,
- CancellationToken = new CancellationTokenSource(TimeSpan.FromHours(3)).Token // Not sure we need such a long time.
+ CancellationToken = new CancellationTokenSource(TimeSpan.FromHours(3)).Token // Not sure we need such a long time. //TODO: This token source is not disposed....
}
);
_logger.LogInformation("Bridge bound to front end name {FrontEndName}", binding.Name);
}
+ private async Task OnActionBlock(RunMethodArgs args)
+ {
+ Result