fix(SbMarkdownEditor): improve disposal handling and error management during editor destruction
- Introduce a _disposed flag to prevent operations on disposed instances. - Enhance error handling in DisposeAsync and editor destruction methods to log exceptions without crashing. - Ensure proper checks before invoking interop methods to maintain stability during component lifecycle events.
This commit is contained in:
@@ -58,19 +58,29 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
private bool _lastIncludeDefaultToolbarItems;
|
private bool _lastIncludeDefaultToolbarItems;
|
||||||
private List<SbMarkdownToolbarItem> _toolbarItems = new();
|
private List<SbMarkdownToolbarItem> _toolbarItems = new();
|
||||||
private bool _useFallback;
|
private bool _useFallback;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
protected bool IsReady { get; private set; }
|
protected bool IsReady { get; private set; }
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
_interop = new SbMarkdownEditorInterop(JSRuntime);
|
_interop = new SbMarkdownEditorInterop(JSRuntime);
|
||||||
_dotNetRef = DotNetObjectReference.Create(this);
|
|
||||||
|
|
||||||
await LoadToolbarItemsAsync();
|
await LoadToolbarItemsAsync();
|
||||||
|
|
||||||
await InitializeEditorAsync();
|
await InitializeEditorAsync();
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_lastRenderedValue = Value;
|
_lastRenderedValue = Value;
|
||||||
_lastRenderedOriginal = OriginalValue;
|
_lastRenderedOriginal = OriginalValue;
|
||||||
_lastRenderedSuggested = SuggestedValue;
|
_lastRenderedSuggested = SuggestedValue;
|
||||||
@@ -149,11 +159,18 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
private async Task InitializeEditorAsync()
|
private async Task InitializeEditorAsync()
|
||||||
{
|
{
|
||||||
|
if (_disposed || _interop == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_dotNetRef ??= DotNetObjectReference.Create(this);
|
||||||
|
|
||||||
if (IsDiffReview)
|
if (IsDiffReview)
|
||||||
{
|
{
|
||||||
_editorId = await _interop!.InitDiffReviewAsync(_diffContainer, _dotNetRef!, new SbMarkdownDiffInitOptions
|
_editorId = await _interop.InitDiffReviewAsync(_diffContainer, _dotNetRef, new SbMarkdownDiffInitOptions
|
||||||
{
|
{
|
||||||
EditorId = _elementId,
|
EditorId = _elementId,
|
||||||
Original = OriginalValue,
|
Original = OriginalValue,
|
||||||
@@ -164,14 +181,19 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _interop!.EnsureAssetsAsync(new SbMarkdownAssetOptions
|
await _interop.EnsureAssetsAsync(new SbMarkdownAssetOptions
|
||||||
{
|
{
|
||||||
EnableMermaid = EnableMermaid,
|
EnableMermaid = EnableMermaid,
|
||||||
EnableHighlight = EnableHighlight,
|
EnableHighlight = EnableHighlight,
|
||||||
HighlightTheme = HighlightTheme
|
HighlightTheme = HighlightTheme
|
||||||
});
|
});
|
||||||
|
|
||||||
_editorId = await _interop.InitEditorAsync(_textarea, _dotNetRef!, new SbMarkdownEditorInitOptions
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_editorId = await _interop.InitEditorAsync(_textarea, _dotNetRef, new SbMarkdownEditorInitOptions
|
||||||
{
|
{
|
||||||
EditorId = GetEditorId(),
|
EditorId = GetEditorId(),
|
||||||
Value = Value,
|
Value = Value,
|
||||||
@@ -189,6 +211,11 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IsReady = !string.IsNullOrEmpty(_editorId);
|
IsReady = !string.IsNullOrEmpty(_editorId);
|
||||||
_useFallback = !IsReady;
|
_useFallback = !IsReady;
|
||||||
}
|
}
|
||||||
@@ -201,6 +228,11 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
private async Task ReinitializeEditorAsync()
|
private async Task ReinitializeEditorAsync()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_editorId != null && _interop != null)
|
if (_editorId != null && _interop != null)
|
||||||
{
|
{
|
||||||
await _interop.DestroyEditorAsync(_editorId);
|
await _interop.DestroyEditorAsync(_editorId);
|
||||||
@@ -210,8 +242,18 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
IsReady = false;
|
IsReady = false;
|
||||||
_useFallback = false;
|
_useFallback = false;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await LoadToolbarItemsAsync();
|
await LoadToolbarItemsAsync();
|
||||||
await InitializeEditorAsync();
|
await InitializeEditorAsync();
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_lastRenderedDiffMode = IsDiffReview;
|
_lastRenderedDiffMode = IsDiffReview;
|
||||||
_lastRenderedValue = Value;
|
_lastRenderedValue = Value;
|
||||||
_lastRenderedOriginal = OriginalValue;
|
_lastRenderedOriginal = OriginalValue;
|
||||||
@@ -388,14 +430,46 @@ public partial class SbMarkdownEditor : ComponentBase, IAsyncDisposable
|
|||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
if (_editorId != null && _interop != null)
|
if (_editorId != null && _interop != null)
|
||||||
{
|
{
|
||||||
await _interop.DestroyEditorAsync(_editorId);
|
try
|
||||||
|
{
|
||||||
|
await _interop.DestroyEditorAsync(_editorId);
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] DestroyEditorAsync JSDisconnected: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] DestroyEditorAsync ObjectDisposed: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] DestroyEditorAsync error: {ex}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_interop != null)
|
if (_interop != null)
|
||||||
{
|
{
|
||||||
await _interop.DisposeAsync();
|
try
|
||||||
|
{
|
||||||
|
await _interop.DisposeAsync();
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] Interop DisposeAsync JSDisconnected: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] Interop DisposeAsync ObjectDisposed: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[SbMarkdownEditor] Interop DisposeAsync error: {ex}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_dotNetRef?.Dispose();
|
_dotNetRef?.Dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user