ASP.Net Core Identity canceled when using FindByIdAsync - asp.net

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?

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.

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.'

Related

I need to call a function from a third-party library from ASP.NET, but it must not be allowed to run asynchronously

This is the situation:
I use a third-party library to do some SPF checks
The checks are done from an ASP.NET web site
The third-party library uses lots of 'await/async' code, although I am calling a non-async method to do it
Most of the time, w3wp (yes, the actual w3wp.exe) simply crashes with the following error ' Invalid token for impersonation - it cannot be duplicated'.
I am assuming this is because the await/async grabbed a Thread from the threadpool which has some sort of illegal / weird identity on it, so I am wondering if there's any way to call a bit of code and tell .Net to 'forget about' async/await and just run it synchronously, on the same thread.
I've found a solution: somewhere in the product the user was being impersonated with identity.impersonate(), but the impersonation context was never .undo()'d. After making sure the identity.impersonate() was properly matched by an .undo(), the problem stopped occurring.
I did try making my own SynchronizationContext, but that didn't work in this instance, as passing on the impersonation just passed on the 'illegal' impersonation context too.

Akka.NET actor system in ASP.NET

I created a service with a RESTful API in ASP.NET, hosted in IIS. Inside this service, I would like to create an actor system with Akka.NET.
Upon creating the actor system:
var actorSystem = ActorSystem.Create("myActorSystem");
The following exception is thrown:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Web.dll
Additional information: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.
The actor system is inherently a concurrent system with asynchronous messages being exchanged between actors. As explained here, this actor system would not survive IIS taking down the AppDomain, which is probably why the aforementioned exception is thrown.
This article explains how to run background tasks in ASP.NET. However, I don't see how I could use this for my actor system, as I have no control over the lifecycle of background tasks that might be created by Akka.NET.
Is there a way to make this work, or should I abandon the idea of having an actor system in an ASP.NET application?
EDIT: I also saw a question on Stackoverflow about implementing a REST service using Akka. Any advice about a solution similar to the Spray toolkit, but working for Akka.NET would be welcome.
I've used Akka.NET and Akka.Remote inside ASP.NET MVC applications that are doing up to 1000 requests per second on EC2 - so I'll share some of the tips and tricks I used to get it up and running successfully. Had a prototype version that even used Akka.Cluster but ended up not shipping that version.
Best place to call ActorSystem.Create is inside Global.asax Application_Start().
Hang onto a static reference to the ActorSystem object inside Global.asax itself, using a static field or property. Helps ensure that the ActorSystem itself doesn't get garbage-collected in long-running applications.
Create a separate static helper class to initialize any top-level actors your applications needs - i.e. actors at the top of the /user/ hierarchy. This class should also provide actor paths that your ASP.MVC controllers and action methods can use for Tell and Ask operations.
Creating the ActorSystem is a bit of an expensive operation, because lots of system-level stuff gets fired up at once. It's definitely best to do this once at application startup and then just cache the result inside the Application class.
Creating individual actor instances is cheap - you should be able to do this no-problem inside ASP.NET MVC action methods. If you see this error come up again, please let us know what part in the request-handling process this error occurred and with which version of ASP.NET.
Edit: added some updated guidance for how to do this on ASP.NET Core
https://petabridge.com/blog/akkadotnet-aspnetcore/
Keep your ActorSystem as a shared property in some static class container - this way you may access it from the rest of your application. Actor system initialization/disposal can be done by:
Global.asax - use ActorSystem.Create(...) inside Global.asax Application_Start and dispose it with system.Shutdown() on Application_End.
OWIN - create actor system in OWIN's Startup.Configuration method and shut it down by binding to host.OnAppDisposing event (how-to link).
Remember that IIS will startup your web app only after first request and tear it down automatically after some time when it's idle. Therefore make sure, that your deployment script will ping application after publishing and set idle timeout (link) for long enough if you want your Akka actor system to run continuously.
Second option
Separate your Actor System logic and deploy it, for example, as a Windows Service (or Linux deamon). Turn on Akka.Remoting for it and create a proxy client, which will forward all application long-running sensitive tasks to external service. Similar solution is often used for things such as schedulers or event buses, when your application logic must be working continuously.

null HttpContext inside SendAsync method of IIdentityMessageService

I have a piece very simple code that used to work before I tried upgrading to ASP.NET Identity. This is a real head-scratcher.
Using ASP.NET MVC 5 with ASP.NET Identity 2.1 (latest-and-greatest at the time of writing this post)
I have a "user forgot their email" controller action that does this:
await this.UserManager.SendEmailAsync(
user.Id,
AccountStrings.ForgotPasswordEmailTitle,
string.Format(AccountStrings.ForgotPasswordEmailMessage, callbackUrl));
My user manager uses an implementation of IIdentityMessageService to shoot out the email and my code is in Task SendAsync(IdentityMessage message). Inside that method I need an active Http context since I'm using the Razor view engine to construct the email. Again, this used to work, until today.
As of today, an exception is thrown inside my method as the email is being rendered telling me I have no active Http context. And sure thing, HttpContext.Current is null. It's not null when the SendEmailAsync is called inside the controller action, it's not null after the await in the task continuation, but it's null inside SendEmailAsync.
I'm using the correct <system.web><httpRuntime targetFramework="4.5.1" /></system.web>
flags inside web.config, everything is by the book. And now, after updating some component - whether it's a minor ASP.NET MVC version or ASP.NET Identity version - I don't know - HttpContext.Current is null.
I have an ugly "fix" where I save the HttpContext.Current to a local var as my IdentityMessageService is created and set the current HttpContext to that value while SendAsync is executing, which works, but this definitely smells like a pretty serious regression inside the ASP.NET stack, somewhere.
Has anyone encountered anything similar?
I have not encountered this exact problem, but my gut feeling say that HttpContext.Current should not be used inside SendEmailAsync and this is not a bug, but intentional implementation on the part of Identity framework. I'll guess that a completely new thread is created just to send out an email and this thread does not have access to HttpContext.Current, i.e. this thread does not depend on the Http request/response.
So my thought would be to decouple your email generation from HttpContext. And to help you do this there is a RazorEngine project that allows to work with Razor views, but without HttpContext. This project is available via nuget:
Install-Package RazorEngine
And judging by the documentation it is pretty easy to work with. I have never used it myself though, so can't go beyond what these web-pages are saying.

ThreadPool.QueueUserWorkItem in Web Service for “Fire and Forget” task

This is ASP.NET ASMX Web Service / .NET Framework 4.0.
In web service, I want to execute one method on another thread something like “Fire and Forget” so that Web Service returns some value in response immediately to web site. That method on another thread could take 10 minutes after Web Service returns response immediately to Web site. Also, I do not need return value of that method.
I have tested this scenario using ThreadPool.QueueUserWorkItem and it seems that thread started using ThreadPool will still keep executing even after Web Service returns response back to Web site. Am I correct here? Also is there a better way to achieve this?
The problem is that every now and then, ASP.NET will recycle the app pool. Because it doesn't know about your background task, it will not be considered and will be aborted when the AppDomain is disposed.
Most of the time, the work will complete, but if you run for long enough, you will encounter this scenario.
There are two solutions:
1) The "proper" way is to write a Windows Service that runs outside ASP.NET. You can send instructions to the Service over WCF.
2) The "quick and dirty" way is to write a hidden web service in your ASP.NET site that is never called by users. Your app starts an asynchronous request to the hidden service and then returns its own result to the user, without waiting.
ASP.NET does not know that the request to the hidden service came from inside your app - it just treats it as another request. Because ASP.NET knows about this request, it will not abort it when it recycles.

ASP.NET Global/Static storage?

I have a thread-safe object which is part of an API previously used in windows service/client scenarios. This thread-safe object is essentially a singleton and stored in a static variable so that all callers can access the same state.
This API has recently started being used in an ASP.NET application, and I suspect that some funky behavior we're seeing may be due to unexpected AppDomain/lifecycle behavior. So I was wondering if I could get some verification:
Is a static variable reliably available for all requests, or does ASP.NET do any trickery with having multiple AppDomains for multiple requests?
I understand this would be the case for a web garden ... but our IIS is configured to use only 1 process, and is configured to only recycle once a day
Static variable should be the same for all requests in 1 worker process. I would suggest you to add logs to your asp.net application, especially in application_start/stop and in static constructor of a singleton to see what's happening.
Hope this helps.

Resources