Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor Server consistent database context between components

I would like to ask which is the best practice for utilizing database context between components? Blazor Server, .Net 5, EF Core 5.0.8

Situation briefly:
Component a, Header
Component b, Main
DbContext is registered as Transient and both of Header and Main have it's own context.

But after eg.: changing data in Main it is not applied for the Header so the data become inconsistent.

Ideas:
1, Remove the DbContext registration and manually create a fresh one for every db call
2, Keep the current architecture, but add an extra call to refresh the data (where needed)
3, Register the DbContext as Scoped and build some kind of queue service around it to process the queries step by step after each other (avoid concurrent calls) and return the result via EventAggregator messages.

What do you think, how do you handle this situation?

like image 752
István Piroska Avatar asked Oct 29 '25 05:10

István Piroska


1 Answers

As per @Liero's answer, I also initially applied use of the IDbContextFactory to create a fresh instance of the context with each service call to the database - however with my app I required Change Tracking across multiple components, and I did not want to break the Unit of Work pattern as this lead to some issues with database in-consistency.

As you mention in step (3) - I keep the DbContext as scoped (AFAIK this is the default), and then I make use of a semaphore to prevent threading issues:

 @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");
                }
            }
        }

This is working really well for my specific use case where I need to retain Change Tracking across components. Here's my full answer from another related question.

like image 86
Daniël Hoffman Avatar answered Nov 01 '25 10:11

Daniël Hoffman