如何同时从不同的 Blazor 组件进行数据调用?
Posted
技术标签:
【中文标题】如何同时从不同的 Blazor 组件进行数据调用?【英文标题】:How do I make data calls from different Blazor components simultaneously? 【发布时间】:2021-06-02 10:48:20 【问题描述】:我是 Blazor 的新手,我正在尝试制作一个包含多个单独组件的页面来处理庞大的表单。每个单独的组件都覆盖了表单的一部分。
我面临的问题是我的每个组件都需要从后端访问数据,而且并非每个组件都使用相同的数据。当页面加载时,每个组件都会尝试从服务器获取数据,这会导致 Entity Framework 出现问题。
在前一个操作之前在此上下文上启动了第二个操作 完全的。这通常是由不同的线程使用相同的 DbContext 的实例。
这显然是由于我的组件是同时初始化的,并且都尝试同时加载数据。我的印象是 Blazor 中设置 DI 的方式,这不是问题,但确实是。
这是我的模板中的组件:
<CascadingValue Value="this">
<!-- BASE DATA -->
<CharacterBaseDataView />
<!-- SPECIAL RULES -->
<CharacterSpecialRulesView />
</CascadingValue>
这是我的组件的初始化方式:
protected async override Task OnInitializedAsync()
CharacterDetailsContext = new EditContext(PlayerCharacter);
await LoadCharacterAsync();
private async Task LoadCharacterAsync()
PlayerCharacter = await PlayerCharacterService.GetPlayerCharacterAsync(ViewBase.CharacterId.Value);
CharacterDetailsContext = new EditContext(PlayerCharacter);
当具有上述代码的两个组件在同一个视图中时,会发生上述错误。我使用同步版本“OnInitialized()”线程并简单地丢弃任务,但这并没有解决错误。
是否有其他方法可以调用数据以避免出现此问题?还是我走错了路?
【问题讨论】:
【参考方案1】:您在 EF 中使用异步操作时遇到了一个常见问题 - 两个或多个操作尝试同时使用相同的上下文。
看看MS Docs article about EF DBContexts - 下面有一个部分专门针对 Blazor。它解释了使用 DbContextFactory
和 CreateDbContext
为 units-of-work 创建上下文,即每个操作一个上下文,因此两个异步操作每个都有一个单独的上下文。
【讨论】:
太好了,解决了。作为未来读者的注意事项:上面提到的文档依赖于 Core 5.0 中提供的函数/类。我仍在使用 3.0,必须升级才能使其正常工作。如果您使用 IdentityFramework,您还需要在 StartUp 类中进行常规上下文实例化。【参考方案2】:最初为了解决线程问题,我使用 DbContextFactory 为每个操作创建上下文 - 但是这导致跨组件的数据库不一致问题,我意识到我需要跨组件跟踪更改。
因此,我将 DbContext 保持在范围内,并且不会在每次操作之前创建新上下文。
然后我调整了我的OnInitializedAsync()
方法来检查对数据库的调用是否已完成,然后再通过我注入的服务进行这些调用。这对我的应用非常有效:
@code
static Semaphore semaphore;
//code ommitted for brevity
protected override async Task OnInitializedAsync()
try
//First open global semaphore
semaphore = Semaphore.OpenExisting("GlobalSemaphore");
while (!semaphore.WaitOne(TimeSpan.FromTicks(1)))
await Task.Delay(TimeSpan.FromSeconds(1));
//If while loop is exited or skipped, previous service calls are completed.
ApplicationUsers = await ApplicationUserService.Get();
finally
try
semaphore.Release();
catch (Exception ex)
Console.WriteLine("ex.Message");
【讨论】:
我的应用程序中的数据流充分分离,几乎不可能在数据中出现不一致,但我同意你的建议可能是最好的方法,如果你想覆盖你的所有基础.我会亲自将您的示例代码移动到一个返回承诺的服务中,这样您就可以按照await ConcurrentCallHelperService.AwaitContextQueueAsync()
的方式做一些事情,因此您需要维护的重复代码更少,但除此之外,这是一个明显的改进。以上是关于如何同时从不同的 Blazor 组件进行数据调用?的主要内容,如果未能解决你的问题,请参考以下文章
如何从服务器端 Blazor 应用程序中的 Blazor 组件调用 razor 页面而不导致页面刷新
Blazor:如何使用来自具有 2 个不同状态的 2 个不同页面的组件