Do I use a JoinableTaskFactory with AspNetCore? - c#

I've imported Microsoft.VisualStudio.Threading into .Net Core Web App. I did this specifically to make use of AsyncLazy<T>.
I wanted to make sure I did this right, so I imported the appropriate Analyzers.
The warnings and the documentation clearly state that a JoinableTaskFactory should be injected into my implementation.
My question is, how should I instantiate that JoinableTaskFactory in the configuration of my .Net Core Web App?
Is it as simple as
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddSingleton(new JoinableTaskFactory());
// ...
}
or, is that all wrong?

Yes, you can use the Microsoft.VisualStudio.Threading library in ASP.NET Core applications. But while JoinableTaskFactory would "work" in such an app, it's a pretty good sign you're doing something wrong.
The analyzers are always appropriate of course, and the warnings you saw were perhaps pointing out that you shouldn't call Task.Result, Task.Wait(), etc. These synchronously block threads and can severely reduce the scalability of your web app (or any app for that matter). You should use await instead wherever possible.
JoinableTaskFactory is there to step in when you can't use await but you still need to call async code. Using JTF.Run will still block the calling thread, but it will do so in a way that avoids deadlocks when you have a single threaded SynchronizationContext in the application. I don't think ASP.NET Core has such a thing, so that's not a concern. JTF.Run is still more efficient than Task.Wait since it can reuse the original thread for continuations instead of a second thread.
If you do choose to use JTF in your web app, if ASP.NET Core doesn't use a single-threaded SynchronizationContext then you can create and share a single JTF instance with the entire app. But if it does have a single-threaded SynchronizationContext, it will be one per web request, which means you need to create a new JoinableTaskContext for each request since these are affinitized to one SynchronizationContext. You always get your JTF instance from a JoinableTaskContext instance.

This page of the vs-threading docs says
The ThreadHelper.JoinableTaskFactory property only works for code running in the VS process. If your code is running out of proc (in the vstest.executionengine.exe runner for instance) it won't work.
So, as the name of the package, Microsoft.VisualStudio.Threading, suggests, it's intended to be used for Visual Studio extensions. The code that you linked for its implementation of AsyncLazy uses JoinableTaskFactory, so it's probably not suitable outside of Visual Studio. I certainly would never use it outside of a VS extension that needs to switch to the UI thread.
Steven Cleary's AsyncEx library has an AsyncLazy, and the wiki page links to this Steven Toub blog post titled AsyncLazy. The blog post points out that the lazy semantics doesn't really add much over what Task<T> provides, although since the value factory might do a lot of work before reaching an await his sample runs it on the thread pool and unwraps the Task<Task<T>>.
edit: As pointed out in the comments, my quote from the docs is somewhat out of context. However, the vs-threading library is about avoiding deadlocks when using async with a synchronisation context (primarily a GUI). ASP.NET Core, what the author of the question is using, does not have a synchronisation context, hence doesn't need to worry about deadlocking the main thread specifically. While using the vs-threading library probably won't cause problems, as my quote claimed, I still don't think it's a good fit for anything without a synchronisation context and there are much better alternatives, like using Task<T> directly and not need any AsyncLazy implementation.

Related

ConfigureAwait(true) in library

I've got an ASP.NET WebForms application which has pages using Async=True and I'm using RegisterAsyncTask(new PageAsyncTask(InitialiseAsync)); in my OnLoad method to call business logic asynchronously.
Now I know ASP.NET WebForms requires async calls to be followed with ConfigureAwait(true) as it needs to return back to the original synchronisation context to finish the page. However the async call chain goes down into a library assembly (also built by us). The library doesn't need to know, nor care about sync contexts to do its asynchronous job. Also, it could (potentially) be used in other contexts such as a Console app.
Therefore:
should the library methods always use ConfigureAwait(true) (in case it's being used by a context sensitive application such as ASP.NET Web Forms)?; or
is it okay for the library methods to use ConfigureAwait(false) and for the WebForms app to use ConfigureAwait(true)?; or
(I'm sure this is not the answer but...) should I pass in a boolean value to the library stating whether to use ConfigureAwait(true) or ConfigureAwait(false)?
I've been using option 1 up until now but I'm now suspecting that I should be using option 2 so that the library code can await back onto any thread and the app will eventually context switch back to the required context thread when the call stack comes back out.
Is that right? Thanks
ConfigureAwait is a decision that only needs to be made per function. If a specific function needs to return to its context, then it should not use ConfigureAwait(false); otherwise, it may use it. Whether the functions caller needs a context is immaterial; when its caller awaits, it can decide for itself whether to use ConfigureAwait(false) or not. So option (3) should never be used.
You can go with option (2), and that's the one that I would choose at this time. ConfigureAwait(false) does have some benefits. However, there is currently an ongoing shift in opinion on this matter, largely driven by the fact that ASP.NET Core does not have a context (so ConfigureAwait(false) is a noop, and people don't like it cluttering up their code). For myself, I still use ConfigureAwait(false) in library code, but some other developers have removed ConfigureAwait(false) from their libraries completely. This is equivalent to your option (1). Either of those options would work; if performance isn't a concern, it just comes down to preference.

How to kill a thread in asp.net core

I am writing an application using asp.net core in which I need to create a new thread as I have an always running loop. At some point, I need to mill this thread. In asp.net, Thread.abort was the solution, but it is removed in asp.net core. What is the alternative solution for this?
Do not create your own thread for something like this!
There is a built-in method for using long running tasks in asp.core. You should read about this here.
You should create a class which derives from BackgroundService. Using this class is the easiest way to create a background-service that implements IHostedService. You can then add this to your program by calling services.AddHostedService<YourBackgroundService>() in the ConfigureServices method.
Note: In the page I linked, they use AddSingleton instead of AddHostedService. In .net core 2.1 and above you should use AddHostedService, not AddSingleton (there are some exceptions but we're talking in general here). See this answer for why that is.
If you implement your background-service like this, the shutdown of the additional thread will be handled for you. In your implementation of ExecuteAsync you need to just check if you should stop executing with the provided CancellationToken. You should also use asnyc implementations where possible and provide the CancellationToken there as well so the thread can end gracefully. You will never need to call Thread.Abort or even have access to the Thread itself; it's all done in the background for you.
Since this is not a direct answer to the question you asked but more of a correction of what you're probably doing wrong to get into this situation in the first place, I first wanted to make this a comment. However it's just too long and there are too many things to mention that's why I made this into an answer.
Hope this helps.
The cleanest way to do this via a flag that is set by the "killing" thread and checked periodically by the thread that needs to be killed. Thread.Abort() is not a reliable way to do it; even the MSDN says Calling this method usually terminates the thread.

Safety of AsyncLocal in ASP.NET Core

For .NET Core, AsyncLocal is the replacement for CallContext. However, it is unclear how "safe" it is to use in ASP.NET Core.
In ASP.NET 4 (MVC 5) and earlier, the thread-agility model of ASP.NET made CallContext unstable. Thus in ASP.NET the only safe way to achieve the behavior of a per-request logical context, was to use HttpContext.Current.Items. Under the covers, HttpContext.Current.Items is implemented with CallContext, but it is done in a way that is safe for ASP.NET.
In contrast, in the context of OWIN/Katana Web API, the thread-agility model was not an issue. I was able to use CallContext safely, after careful considerations of how correctly to dispose it.
But now I'm dealing with ASP.NET Core. I would like to use the following middleware:
public class MultiTenancyMiddleware
{
private readonly RequestDelegate next;
static int random;
private static AsyncLocal<string> tenant = new AsyncLocal<string>();
//This is the new form of "CallContext".
public static AsyncLocal<string> Tenant
{
get { return tenant; }
private set { tenant = value; }
}
//This is the new verion of [ThreadStatic].
public static ThreadLocal<string> LocalTenant;
public MultiTenancyMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
//Just some garbage test value...
Tenant.Value = context.Request.Path + random++;
await next.Invoke(context);
//using (LocalTenant = new AsyncLocal<string>()) {
// Tenant.Value = context.Request.Path + random++;
// await next.Invoke(context);
//}
}
}
So far, the above code seems to be working just fine. But there is at least one red flag. In the past, it was critical to ensure that CallContext was treated like a resource that must be freed after each invocation.
Now I see there is no self-evident way to "clean up" AsyncLocal.
I included code, commented out, showing how ThreadLocal<T> works. It is IDisposable, and so it has an obvious clean-up mechanism. In contrast, the AsyncLocal is not IDisposable. This is unnerving.
Is this because AsyncLocal is not yet in release-candidate condition? Or is this because it is truly no longer necessary to perform cleanup?
And even if AsyncLocal is being used properly in my above example, are there any kinds of old-school "thread agility" issues in ASP.NET Core that are going to make this middleware unworkable?
Special Note
For those unfamiliar with the issues CallContext has within ASP.NET apps, in this SO post, Jon Skeet references an in-depth discussion about the problem (which in turn references commentary from Scott Hanselman). This "problem" is not a bug - it is just a circumstance that must be carefully accounted for.
Furthermore, I can personally attest to this unfortunate behavior. When I build ASP.NET applications, I normally include load-tests as part of my automation test infrastructure. It is during load tests that I can witness CallContext become unstable (where perhaps 2% to 4% of requests show CallContext being corrupted. I have also seen cases where a Web API GET has stable CallContext behavior, but the POST operations are all unstable. The only way to achieve total stability is to rely on HttpContext.Current.Items.
However, in the case of ASP.NET Core, I cannot rely on HttpContext.Items...there is no such static access point. I'm also not yet able to create load tests for the .NET Core apps I'm tinkering with, which is partly why I've not answered this question for myself. :)
Again: Please understand that the "instability" and "problem" I'm discussing is not a bug at all. CallContext is not somehow flawed. The issue is simply a consequence of the thread dispatch model employed by ASP.NET. The solution is simply to know the issue exists, and to code accordingly (e.g. use HttpContext.Current.Items instead of CallContext, when inside an ASP.NET app).
My goal with this question is to understand how this dynamic applies (or does not) in ASP.NET Core, so that I don't accidentally build unstable code when using the new AsyncLocal construct.
I'm just looking into the source code of the ExecutionContext class for CoreClr:
https://github.com/dotnet/coreclr/blob/775003a4c72f0acc37eab84628fcef541533ba4e/src/mscorlib/src/System/Threading/ExecutionContext.cs
Base on my understanding of the code, the async local values are fields/variables of each ExecutionContext instance. They are not based on ThreadLocal or any thread specific persisted data store.
To verify this, in my testing with thread pool threads, an instance left in async local value is not accessible when the same thread pool thread is reused, and the "left" instance's destructor for cleaning up itself got called on next GC cycle, meaning the instance is GCed as expected.
Adding my two cents if someone lands on this page (like I did) after googling if AsyncLocal is "safe" in ASP.NET classic (non Core) application (some commenters have been asking this, and also I see a deleted answer asking about the same).
I wrote a small test that simulates asp.net's ThreadPool behavior
AsyncLocal is always cleared between requests even if thread pool re-uses an existing thread. So it is "safe" in that regard, no data will be leaked to another thread.
However, AsyncLocal can be cleared even within the same context (for example between code that runs in global.asax and the code that runs in controller). Because MVC-methods sometimes runs on a separate thread from non-MVC code, see this question for example: asp.net mvc 4, thread changed by model binding?
Using ThreadLocal is not safe b/c it preserves the value after the thread from Thread Pool is re-used. Never use ThreadLocal in web-applications. I know the question is not about ThreadLocal I'm just adding this warning to whoever considering using it, sorry.
Tested under ASP.NET MVC 5 .NET 4.7.2.
Overall, AsyncLocal seems like a perfect alternative to short-time caching stuff in HttpContext.Current in cases where you can't access the latter directly. You might end up re-calculating the cached value a bit more often though, but that's not a big problem.

In async/await, what are the repercussions of not returning to context thread?

Using async/await as shown here http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html, one of the good practices is using ConfigureAwait(false) so the method return does not have to come back to the request context. What are the potential consequences of using this? Asked another way, when would this not be recommended?
when would this not be recommended?
Your method must return to the same context if there's code further down in the method that depends on that context. If the remainder of that method does not require a particular context, then it's a good practice to use ConfigureAwait(false).
There are two primary examples: UI code and ASP.NET code.
UI code must run on the UI thread; this includes most UI widget access, and I extend the definition of "UI code" to include my ViewModels as well (there are some situations in WPF where you can get away with updating the UI from a background thread, but that's not true for all MVVM platforms). So, if your method ends with a textBox1.Text = "" or a myViewModel.MyObservableCollection.Add(4), then it has to return to the UI thread before it can execute that code.
ASP.NET code must run in an ASP.NET request context; this includes any code that depends on HttpContext.Current (and many System.Web APIs implicitly assume an ASP.NET request context). So, if your method ends with HttpContext.Current.Items..., then it has to return to the ASP.NET request context before it can execute that code. (Side note: in ASP.NET vNext on .NET 4.6 and higher, the ASP.NET request context is actually going away).
In practice, what this means is that most library code should use ConfigureAwait(false), since well-written library code does not have a dependency on a particular UI framework or System.Web. Similarly, most application code should not use ConfigureAwait(false), since it has to update the UI / send an HTTP response.

Implicitly scoped context in multi-threaded MVVM application

I'm working on a WPF application with heavy multi-threading using a bit of async/await. I'm pondering the use of Unit of Work pattern (with implicit scoping) within the client (having it work much like a TransactionScope), but can't decide where to store the context.
Some things I've considered:
Thread locals; but that won't work as we may switch threads in a nested unit of work.
Static; I believe this will fail if two unrelated unit of works are executed at the same time
In my service layer (webapi odata), I attach the unit of work to the http context to allow nesting across threads. Has anyone tried something like this in a client app and have a decent way of scoping nested units of work?
Unit of Work doesn't necessarily mean that the context is implicit (or scoped, for that matter). I believe it's quite normal for UoW to be explicit (e.g., your BO types would keep a reference to their "owning" context, which is itself threadsafe). That said, an implicit context is possible with async.
When you use await only in an ASP.NET request context, the best option is to use HttpContext.Items. Alternatively, you could use threadsafe static members.
When you use await only in a UI context, you could use regular static members.
When you use multithreading, you could use thread locals.
However, if any of your code uses multithreading with await (e.g., ConfigureAwait(false), or passing an async lambda to Task.Run), then none of those options will work.
AFAIK, there is only one general solution, which I describe on my blog: CallContext.LogicalGetData and CallContext.LogicalSetData. The logical call context will flow across threads and would work in any async situation.
There are some limitations to this approach:
You must use the .NET 4.5 framework. CallContext was made async-aware in .NET 4.5, so if you're targeting .NET 4.0 / Phone / Silverlight, this won't work correctly.
You should only store immutable data. This is made much easier if you use Microsoft.Bcl.Immutable.

Categories

Resources