1
votes

I am new to using dependency injection and had come a long way in my blazor project before I really started using it.

I added DBContext as Transient service(as mentioned in many answers here) and injected it into DataAccessLayer like so:

     public class DataAccessLayer
    {
        public DataAccessLayer(GlobalVariables s,DataContext d)
        {
            GlobalVariables = s;
            context = d;
        }

        private readonly GlobalVariables GlobalVariables;
        private readonly DataContext context;
`/other code here`

Now as I am using razor components in my blazor project when I open one page, around 5 components start to render. All of these components are fetching data from DataAccessLayer.

I run getting these two errors:

System.InvalidOperationException: Invalid attempt to call ReadAsync when reader is closed.

System.InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext

When i remove the dependency and add (using Datacontext), the errors go away and it runs fine. Can anybody suggest me how to properly inject it?

P.S: I have already checked that all my async methods have await and configureawait(true)

The method throwing the first exception of readasync is this :

public async Task<List<MasterCustomer>> getCustomersBinding()
    {
        List<MasterCustomer> customersList = new List<MasterCustomer>();

        {
            customersList = await (from table in context.MasterCustomer where (table.IsActive == true) select (new MasterCustomer { Code = table.Code, Name = table.Name })).ToListAsync().ConfigureAwait(true); ;
        }
        return customersList;
    }
2
Where do you call ReadAsync? Could you show the code of that methodVencovsky
Edited the question to add the asked code at the end of it.Tanveer Khan
My answer with a link to official guidance to use EF with Blazor Server Side.dani herrera

2 Answers

1
votes

Your DataAccess layer needs to be transient too, otherwise you'll get a scoped instance that always holds onto the first transient instance of DbContext created.

Finally, make sure you descend your component from OwningComponentBase<T>, otherwise your injected dependency won't be disposed.

@inherits OwningComponentBase<DataAccessLayer>

Then you can access DataAccessLayer via this.Service, and this.Service will be disposed of when your component is disposed.

https://blazor-university.com/dependency-injection/

0
votes

configureawait(true) is useless in ASP.NET Core.

To avoid threading issue with Entity Framework Core and injected context, inject instead IServiceScopeFactory and use the following pattern

      using (var scope = _scopeFactory.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

                do whatever you want with dbContext
            }