Open sbwalker opened 5 months ago
Thanks for bringing this up, @sbwalker. Have you seen my response in https://github.com/dotnet/aspnetcore/issues/54539#issuecomment-2007652901? Maybe that addresses this too?
@mkArtakMSFT I don't think it does address the issue. I am developing Static Server-Side components and when I use EF Core for data access I was running into exceptions:
"System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first."
I consulted the documentation which mentions "server-side Blazor apps":
"In server-side Blazor apps, DbContext isn't thread safe and isn't designed for concurrent use. The existing lifetimes are inappropriate for these reasons:
By default, consider using one context per operation. The context is designed for fast, low overhead instantiation:
using var context = new MyContext(); return await context.MyEntities.ToListAsync();"
So I modified my code to use DbContextFactory and it fully resolved my issue.
So in my experience DbContextFactory needs to be used in Static Server-Side Blazor as well as Interactive - Blazor Server scenarios.
Is there an existing issue for this?
Describe the bug
The latest guidance from Microsoft for using EF Core with Blazor is to use DbContextFactory and short-lived DbContent instances (confirmed here https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-ef-core?view=aspnetcore-8.0#new-dbcontext-instances).
The basic pattern is to use CreateDbContext() in your data access methods. The following is an example of method which returns a collection of users:
Note that when using this pattern it is not possible to use the standard EF Core lazy loading behavior. This is because the DbContext is disposed as soon as the data access is complete. If you try to defer performing any additional operations on the DbSet it will throw an exception. For example if we add an .OrderBy():
It will result in the following exception:
"Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances."
The solution to this problem is to add .ToList() to instruct EF Core to perform eager loading on the collection:
However this means that your Blazor application will not be able to utilize lazy loading, which is one of the most significant performance features offered by EF Core.
Since DbContextFactory is the recommended guidance, I was curious how aspnetcore handled this challenge in its own classes which interact with EF Core. A few examples:
The new CRUD templates for Blazor which were introduced recently for scaffolding code. It appears they do not follow the guidance - they continue to use DbContext (which has been well documented to to not align with Blazor's process model). In fact someone already logged an issue about this: https://github.com/dotnet/aspnetcore/issues/54539
The .NET Identity classes in .NET 8. It appears they do not use DbContextFactory either. Someone has logged an issue here: https://github.com/dotnet/aspnetcore/issues/42260
So since there are no examples on the recommended approach for using DbContextFactory, I would request that the documentation be updated with some examples. Specifically, it would be helpful if this challenge related to lazy loading is addressed in the docs so that it is clear on whether Microsoft is recommending that developers utilize an eager loading approach with EF Core when it comes to Blazor.
Expected Behavior
Improved documentation and actual DbContextFactory usage in aspnetcore implementations.
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
8.0
Anything else?
No response