rudolfdobias
rudolfdobias

Reputation: 1958

An operation is already in progress error while accessing DB from middleware

Hello,

I have an ASP.NET Core app with EF Core running on postgresql db server. I ran into this problem:

When I access DB from a controller, everything works fine. But when I try to access DB from a middleware, an exception occurs (both under higher request load):

System.InvalidOperationException: An operation is already in progress.
   at Npgsql.NpgsqlConnector.StartUserAction(ConnectorState newState)
   at Npgsql.NpgsqlCommand.<ExecuteDbDataReaderInternalAsync>d__4.MoveNext()
...

Sample code:


DB configuration

private void ConfigureDatabase(IServiceCollection services)
{
    var connectionString = ConfigObject.Value.DbContextSettings.ConnectionString;
    services.AddDbContext<ApplicationDbContext>(opts => opts.UseNpgsql(connectionString));
}

DbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, Guid>
  {

        ...

        public DbSet<SomeItem> SomeItems { get; set; }

        ...
  }

The middleware

public async Task Invoke(HttpContext context)  
        {
                var test = await _context.SomeItems.FirstOrDefaultAsync();
        }

An controller

public async Task<SomeItem> GetStuff()  
        {
                return await _context.SomeItems.FirstOrDefaultAsync();
        }

My question is - Why is the controller able to serve many async concurrent request and the middleware not? And how can I get it work too? I'm little bit lost in asynchronicity and ASP.NET anatomy right now.

Thank you in advance.

Upvotes: 0

Views: 838

Answers (2)

adem caglin
adem caglin

Reputation: 24123

When you use constructor injection in middleware, if dependency lifetime is scoped it causes captive dependency. You used ApplicationDbContext and it is scoped. So the problem probably occurs from this reason. To avoid, you can pass dependency into Invoke method as a parameter:

    public async Task Invoke(HttpContext context, ApplicationDbContext _context)  
    {
         var test = await _context.SomeItems.FirstOrDefaultAsync();
    }

Upvotes: 1

Michael Puckett II
Michael Puckett II

Reputation: 6749

I'm not sure why you're getting the error but both methods aren't the same. middleware doesn't have a return type and controller does 'SomeItem'. Also, just return the Async method right away and drop the asnyc await from the Task.

public async Task GetStuff()
{ return await _context.SomeItems.FirstOrDefaultAsync(); }

public Task<SomeItem> GetStuff()  
{
    return _context.SomeItems.FirstOrDefaultAsync();
}

Upvotes: 0

Related Questions