EF. The connection was not closed. The connection’s current state is connecting

I have jwt auth:

var messageHandlers = new JwtMessageHandler(_serviceProvider);

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    Events = new JwtBearerEvents
    {
        OnMessageReceived = messageHandlers.OnMessageReceived,
    },
    TokenValidationParameters = tokenValidationParameters
});

The JwtMessageHandler is my custom handler. In the handler I have to make some queries to database, so I pass ServiceProvider and resolve my user service:

public class JwtMessageHandler
{

        private IUserService _userService;  

        public async Task OnMessageReceived(MessageReceivedContext arg)
        {
             //parsing header, get claims from token
             ...
              _userService = (IUserService)arg.HttpContext.RequestServices.GetService(typeof(IUserService));
             var isRoleChanged = await _userService.IsRoleChanged(tokenObject.Subject, rolesFromToken);

            if (isRoleChanged)
            {
                GenerateBadResponse(arg);
                return;
            }

            var canLogin = await _userService.CanLogin(tokenObject.Subject);

            if (!canLogin)
            {
                GenerateBadResponse(arg);
                return;
            }
        }    
}

In the service I make queries:

...
 var user = await _userManager.FindByEmailAsync(email);
 var currentRoles = await _userManager.GetRolesAsync(user);
..

The OnMessageReceived is called for every request.
When I have one request on page to the server or I wait one-two seconds before doing something all works fine. But, I have several pages where I make 2-3 simultaneous requests to the server. And, in this case I get error about:

The connection was not closed. The connection’s current state is connecting

I understand that problem with multithreading. The JwtMessageHandler is created once when application is started. So, I put the line:

_userService = (IUserService)_serviceProvider.GetService(typeof(IUserService));

inside method, before it was located in the constructor. But, It didn’t help. Also, I tried to set null to _userService in the end of my method.

How to correctly use in this case?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Trying to use a connection that is already “connecting” – clear sign of some race condition.

  1. Re-check that IUserService is registered with “scope” lifetime, and all it dependencies (userManager, dbContext) too
  2. Do not use IServiceProvider you obtained during app startup for scope-bases services resolution – it is NOT related to current request scope and return instances from “some other universe”. Use HttpContext.RequestServices for service resolution.
  3. Check that your are “awaiting” all async methods. If you start second request while still executing first one – you may possibly “catch” dbContext during “connecting” stage.
  4. Your JwtMessageHandler instance is one/single per app. So don’t use it’s property for storing _userService (remove private IUserService _userService). Instead, use local variable inside OnMessageReceived (var _userService = ...).

You already checked (1), (2) and (3). I think (4) is the last one you need to fix your bug.

Method 2

@Dmitry’s answer pointed me in the right direction. For me, I was having this issue in a MiddleWare on .NETCORE. What solved this issue for me is resolving the IUnitOfWork interface in the Invoke method of my Middleware.

I did something like

public Task Invoke(HttpContext context)
{
    _unitOfWork = (IUnitOfWork)context.RequestServices.GetService(typeof(IUnitOfWork));

       //Some checks            

        var apiKey = context.Request.Headers["X-ApiKey"][0];

        var clientApp = _unitOfWork.ClientApplicationsRepository.Items.FirstOrDefault(s => s.ApiKey == apiKey);

     //Some other code...

    return _next(context);
}

Method 3

I have faced this situation a lot.
I have always gotten by by using lock keyword.

lock (_context)
{
      var user = _context.users.first(x => x.Id == userId);
}

This locks the use of the object (i.e. _context) for the current thread and no other thread simultaneously can access this same instance hence no problems whatsoever.

Method 4

In my case I was trying to use Managed Identity and constructed a SqlConnection in ConfigureServices and did AddDbContext<..>(o => o.UseSqlServer(sqlConnection);

That resulted in strange behaviour.

Fixed it by moving the code to the Context OnConfiguring

        var sqlConnection = new SqlConnection(Startup.Configuration.GetConnectionString("xxx"));
        optionsBuilder.UseSqlServer(sqlConnection);


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x