diff --git a/backend/FwLite/FwLiteShared/FwLiteSharedKernel.cs b/backend/FwLite/FwLiteShared/FwLiteSharedKernel.cs index 5927b79ff..6072d9dfd 100644 --- a/backend/FwLite/FwLiteShared/FwLiteSharedKernel.cs +++ b/backend/FwLite/FwLiteShared/FwLiteSharedKernel.cs @@ -21,7 +21,9 @@ public static IServiceCollection AddFwLiteShared(this IServiceCollection service services.AddScoped(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + //this is scoped so that there will be once instance per blazor circuit, this prevents issues where the same instance is used when reloading the page. + //it also avoids issues if there's multiple blazor circuits running at the same time + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); diff --git a/backend/FwLite/FwLiteShared/Pages/CrdtProject.razor b/backend/FwLite/FwLiteShared/Pages/CrdtProject.razor index bb320bd0c..59a3be620 100644 --- a/backend/FwLite/FwLiteShared/Pages/CrdtProject.razor +++ b/backend/FwLite/FwLiteShared/Pages/CrdtProject.razor @@ -5,6 +5,8 @@ @inherits OwningComponentBaseAsync @layout SvelteLayout; @inject IJSRuntime JS; +@* injecting here means we get a provider scoped to the current circuit *@ +@inject FwLiteProvider FwLiteProvider; @code { @@ -16,8 +18,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; - var fwLiteProvider = ScopedServices.GetRequiredService(); - _disposable = await fwLiteProvider.InjectCrdtProject(JS, ScopedServices, ProjectName); + //scoped services here are per page render, meaning they will get cleaned up when the page is disposed + _disposable = await FwLiteProvider.InjectCrdtProject(JS, ScopedServices, ProjectName); } protected override async ValueTask DisposeAsyncCore() diff --git a/backend/FwLite/FwLiteShared/Pages/FwdataProject.razor b/backend/FwLite/FwLiteShared/Pages/FwdataProject.razor index c002ec062..dbae36bb9 100644 --- a/backend/FwLite/FwLiteShared/Pages/FwdataProject.razor +++ b/backend/FwLite/FwLiteShared/Pages/FwdataProject.razor @@ -5,6 +5,7 @@ @inherits OwningComponentBaseAsync @layout SvelteLayout; @inject IJSRuntime JS; +@inject FwLiteProvider FwLiteProvider; @code { @@ -16,8 +17,7 @@ protected override Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return Task.CompletedTask; - var fwLiteProvider = ScopedServices.GetRequiredService(); - _disposable = fwLiteProvider.InjectFwDataProject(ScopedServices, ProjectName); + _disposable = FwLiteProvider.InjectFwDataProject(ScopedServices, ProjectName); return Task.CompletedTask; } diff --git a/backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs b/backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs index 8584837f3..9a7cb5099 100644 --- a/backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs +++ b/backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs @@ -127,11 +127,11 @@ public IAsyncDisposable InjectFwDataProject(IServiceProvider scopedServices, str private IDisposable ProvideMiniLcmApi(MiniLcmJsInvokable miniLcmApi) { var reference = DotNetObjectReference.Create(miniLcmApi); - _miniLcmApiProvider.SetMiniLcmApi(reference); + var cleanup = _miniLcmApiProvider.SetMiniLcmApi(reference); return Defer.Action(() => { - reference?.Dispose(); - _miniLcmApiProvider.ClearMiniLcmApi(); + reference.Dispose(); + cleanup.Dispose(); }); } } @@ -151,10 +151,19 @@ public async Task> GetMiniLcmApi() #pragma warning restore VSTHRD003 } - public void SetMiniLcmApi(DotNetObjectReference miniLcmApi) + public IDisposable SetMiniLcmApi(DotNetObjectReference miniLcmApi) { logger.LogInformation("Setting MiniLcmApi"); _tcs.SetResult(miniLcmApi); + var currentTask = _tcs.Task; + return Defer.Action(() => + { + //if the tcs has been reset, then we don't want to clear it again + if (_tcs.Task == currentTask) + { + ClearMiniLcmApi(); + } + }); } [JSInvokable]