Multiple Blazor components accessing database via single DbContext at same time
What is the most straightforward way to handle multiple Blazor components trying to access the database via a DbContext in EF Core at once? I'm creating an indeterminate number of components on a page at once that all make a call within
OnInitializedAsync()
to a scoped service in order to pull a record from the database. A problem seems to arise from the fact that they are all using the same DbContext, which is not thread safe? Can someone point me in the right direction? Hopefully that's not too broad a question, still new to this area .13 Replies
I'm seeing some recommendations of using a DbContextFactory - would that be the best solution?
yes, you can't use a dbcontext concurrently and since blazor's scoped lifetime is more like a singleton lifetime the factory is the way to go
in my current project i just don't access the db from components directly and use mediatr and a helper service to put each logical "request" in a new service scope
I've had a think about it, and I think this is the only instance in my application where this problem will occur. Since I'm only needing access to a couple of strings (Title and Description of the relevant model), I've decided just to get the object in the parent component and then pass the Title and Description to the child components directly, avoiding concurrent calls to dbcontext. I think this maybe breaks some "rules" regarding security, but since these strings don't contain any sensitive information, I think it's probably okay. Would you agree? Avoids adding a layer of complexity to the project and gets the same job done
the other problem is the fact you're holding onto the dbcontext longer than intended, you aren't supposed to keep reusing the same one because the change tracker will get bloated/stale
it shouldn't really live longer than one "thing" being done
How much of a problem is that likely to be? This is for a university project and won't actually be running for too long at once. I'm assuming that'd be more of an issue for an application that's running for long periods of time?
Just trying to balance between best practices/ease of development/simplicity due to the time constraints. Cutting a few corners where acceptable
IMO the value of doing it right the first time and not having to rewrite it later if you run into an issue is better than the convenience of ignoring it now
using the factory is essentially just an extra line of code
If it's pretty straightforward, maybe I'll look further into it then - my main concern was that I'd have to rewrite a chunk of logic
no, you basically just inject
IDbContextFactory<YourDbContext>
and call await using var db = await factory.CreateDbContextAsync()
to get a dbcontext when you need oneWow, that' s a lot simpler than I was expecting. I was having a skim read of some StackOverflow threads covering this topic and there seemed to be a lot of try-catch stuff bloating the code... not sure what they were doing to end up with that, my first thought was "that isn't very DRY". Seems it's definitely worthwhile then, I'd of course like to use best practices wherever I can as long as it doesn't add a ton of complexity
you wouldn't need any more error handling than using the directly injected dbcontext
I assume the change to my services (e.g.):
Would be as simple as just passing the context to the CRUD methods rather than having it in the service constructor?
Or would it be better to actually create a new context inside of each CRUD method, rather than passing it in?
inject the factory, use it to create a dbcontext for each call
Awesome, I'll have a go at it - it sounds simple enough and will give me a bit more flexibility at the very least. Thanks for the help
Made the change, tested that existing functionality was behaving as before and checked if the code that was causing issues with concurrency is now working - everything seems fine, very simple change and can't see any problems yet. Awesome stuff :goodthinking: