5

I'm have a small project that uses the Asp.Net Core Identity framework together with EF Core. One function calls the UserManager.FindByIdAsync(id) and it returns the proper object. However, it only works a few minutes after the application is started. As long as the server is busy it works fine, but as soon as the application is idle more than 1-2 minutes the request fails.

It fails with:

*OperationCanceledException: The operation was canceled.
System.Threading.CancellationToken.ThrowOperationCanceledException()*

The stacktrace looks like this:

*System.Threading.CancellationToken.ThrowOperationCanceledException()
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore.FindByIdAsync(string userId, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.UserManager.FindByIdAsync(string userId)
MyProject.Areas.Admin.ControllerServices.UserService+<GetUser>d__11.MoveNext() in UserService.cs*

I'm still logged in as other pages are working fine. A simple call to the EF context.Users.FindAsync(new object[] { id }) will work as expected, but the next line containing FindByIdAsync will fail.

All this works perfect in the dev environment, the error occurs when the application is installed on the server running IIS on WS 2008 R2. Recycling the app pool will make it work again until it is idle again for a few minutes.

I have noted that when lines like 'Connection id "0HL5E91K33IIQ" reset.' are being logged, then the app starts to fail. Prior to that it works.

FindByIdAsync is not the only identity function to fail, many other functions fails with the same error.

What am I missing?

4
  • Same for me, when a REST client test is executed a second time during second logon (all local). Very annoying, stack trace is no help at all. Commented Jun 28, 2017 at 18:21
  • 1
    Same for me since... today! It was fine before. Commented Jun 28, 2017 at 19:22
  • Update: running in IIS Express does not show that behavior, only Kestrel. In my case it's netfx 4.6 and asp.net core 1.1 Commented Jun 28, 2017 at 23:28
  • Update: had nothing to do with Kestrel or IIS, see my answer below Commented Jul 24, 2017 at 16:01

2 Answers 2

8

I will answer my own question, and hopefully this will help someone else in the future.

For me, it all boiled down to the lifetime of the injected services. UserManager depends on IHttpContextAccessor (this is where the CancellationToken comes from) and it behaves incorrectly when lifetimes do not match up. IHttpContextAccessor is added as a Singleton service, while the UserManager is added as a scoped service. My service that used the UserManager was added as a Singleton service. Changing this to Scoped made the errors go away.

Sign up to request clarification or add additional context in comments.

Comments

0

In my case it boiled down to the exact same issue, but was caused by a very subtle design "flaw" in ASP.Net Core's DI implementation. For various reasons I prefer using SimpleInjector, but stuffing ASP.Net Identity Core into it is hard, compared to the nice extension methods provided for the build in container. So I put the framework stuff in the framework container, and my business stuff in SimpleInjector, deciding that "Authentication and Authorization" is considered "framework". Only the AccountController is resolved by the framework container using cross wiring. However, using app.ApplicationServices.GetService<AccountController>() outside a request scope does not fail but returns a Singleton that will survive! Unfortunately exactly this happens when you let SimpleInjector verify it's configuration. The first request causing a malfunction (bad login) leaves your whole runtime with a defect singleton instance. Solution for this is well documented in SimpleInjectors documentation, use their extension app.GetRequiredRequestService<AccountController>() instead.

Update asp.net core 2.0

Now, you won't get the fishy singleton instance, but an exception: System.InvalidOperationException: 'Cannot resolve scoped service 'WebApplication15.Controllers.AccountController' from root provider.'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.