Start a task with clean AsyncLocal state - asp.net-core

In ASP.NET Core, I am using IHttpContextAccessor to access the current HttpContext. HttpContextAccessor uses AsyncLocal<T>.
In one situation, I am trying to start a Task from within a request, that should continue running after the request has ended (long running, background task), and I am trying to detach it from the current execution context so that IHttpContextAccessor returns null (otherwise I am accessing an invalid HttpContext).
I tried Task.Run, Thread.Start, but every time, the context seems to carry over and IHttpContextAccessor returns the old context whatever I try (sometimes even contexts from other requests 🤔).
How can I start a task that will have a clean AsyncLocal state so that IHttpContextAccessor returns null?

Late answer but might be useful for someone else. You can do this by suppressing the ExecutionContext flow as you submit your task:
ExecutionContext.SuppressFlow();
var task = Task.Run(async () => {
await LongRunningMethodAsync();
});
ExecutionContext.RestoreFlow();
or better:
using (ExecutionContext.SuppressFlow()) {
var task = Task.Run(async () => {
await LongRunningMethodAsync();
});
}
This will prevent the ExecutionContext being captured in the submitted task. Therefore it will have a 'clean' AsyncLocal state.
As above though I wouldn't do this in ASP.net if it's CPU intensive background work.

You could await the long running task and set HttpContext to null inside await. It would be safe for all code outside the task.
[Fact]
public async Task AsyncLocalTest()
{
_accessor = new HttpContextAccessor();
_accessor.HttpContext = new DefaultHttpContext();
await LongRunningTaskAsync();
Assert.True(_accessor.HttpContext != null);
}
private async Task LongRunningTaskAsync()
{
_accessor.HttpContext = null;
}
You could run a separate thread, it doesn't matter.
Task.Run(async () => await LongRunningTaskAsync());
Just make the task awaitable to cleanup HttpContext for the task's async context only.

Related

How to guard against double trigger of async method in Blazor wasm

I'm developing a blazor wasm application. I'm struggling with an async issue - that I find difficult to tackle, as the threading in the browser is not completely clear to me. I'm not using any async voids - everything is async Task.
From an API call (async) I get back two objects. One object I dispatch as an synchronous update to the fluxor store, and the other I have to do a async call on the local Indexdb, after which this one also enters the fluxor store.
The two fluxor store updates trigger via an event an update method of the view model. This update method is async, as it also get's some info from the IndexedDb. This async method fetches async some items from Indexdb, clears a dictionary, then enumerates over a property of the fluxor store to update the model.
This method get's called twice in quick succession, and as a result, starts interweaving.
The trouble is the first method call is paused during the enumeration over the state, next the second method call clears the dictionary, and starts it's own enumeration (and finishes), after which the first method resumes midst it's earlier started enumeration.
This results in errors - trying to add identical keys twice to the dictionary.
How can I guard against this?
How can I prevent the same method call to interweave with itself in Blazor wasm?
How can the (synchronous) enumeration part of the async update method be paused, allowing the full method to run, and next resuming the first call again?
public partial class DebugPage : BasePage, IDisposable
{
[Inject] IState<MonthBalanceState> MonthBalanceState { get; set; }
private Dictionary<IMonthBalanceAddress, int> DbCountDictionary = new Dictionary<IMonthBalanceAddress, int>();
protected override async Task OnParametersSetAsync()
{
MonthBalanceState.StateChanged += async (_, _) => await MonthBalanceState_StateChanged();
Console.WriteLine($"Linkage made to Monthbalance State");
await base.OnParametersSetAsync();
}
//This method get's called twice quickly - starting the interweaving
private async Task MonthBalanceState_StateChanged()
{
Console.WriteLine($"Update via Statechanged Monthbalance State");
var result = await UpdateDictionaryAsync();
}
private async Task<bool> UpdateDictionaryAsync()
{
DbCountDictionary.Clear();
Log.Debug("Debug dictionary updated");
foreach (IMonthBalanceLoadable mb in MonthBalanceState.Value.MonthBalances.ToList())
{
Console.WriteLine($"Adding {mb.Address.ToString()}");
DbCountDictionary.Add(mb.Address, await Db.GetCountByAddress(mb.Address));
}
return true;
}
+= async (_, _) => await MonthBalanceState_StateChanged();
This lambda is an async void wrapping your handler.
So the whole is not awaited and that is the source of your problem.
That StateChanged event should probably be an EventCallback property. Post the relevant code if you need more help.
If possible, you could use OnAfterRenderAsync(bool firstRender) instead if OnParametersSetAsync() and then only set you variables if it is the first render.

FindAsync never comes back however Find works just fine

I am using FluentValidation to validate the objects. I am simply checking checking whether the user exists in database or not. In my case, DbContext.Entity.Find works just fine but DbContext.Entity.FindAsync never returns.
Please refer to the below source code where it is happening.
public class ChangeStatusOfUserCommandValidator : AbstractValidator<ChangeStatusOfUserCommand>
{
private readonly FieldSellDbContext dbContext;
private ChangeStatusOfUserCommandValidator()
{ }
public ChangeStatusOfUserCommandValidator(FieldSellDbContext databaseContext)
{
dbContext = databaseContext;
RuleFor(u => u.UserId).NotEmpty();
RuleFor(u => u.UserId).MustAsync(UserExists).WithMessage("Provided user id already exists in the database.");
}
public async Task<bool> UserExists(int value, CancellationToken cancellationToken)
{
var user = await dbContext.Users.FindAsync(value, cancellationToken);
//var user = dbContext.Users.Find(value); --Works fine even in async method
return user != null;
}
}
Thanks
Your problem is almost certainly further up your call stack, where the code is calling Task<T>.Result, Task.Wait(), Task.GetAwaiter().GetResult(), or some similar blocking method. If your code blocks on asynchronous code in a single-threaded context (e.g., on a UI thread), it can deadlock.
The proper solution is to use async all the way; that is, use await instead of blocking on asynchronous code. Fluent validation has an asynchronous workflow (e.g., ValidateAsync, MustAsync), so you'll need to be sure to use that rather than the synchronous APIs.

StackExchange.Redis transaction methods freezes

I have this code to add object and index field in Stackexchange.Redis.
All methods in transaction freeze thread. Why ?
var transaction = Database.CreateTransaction();
//this line freeze thread. WHY ?
await transaction.StringSetAsync(KeyProvider.GetForID(obj.ID), PreSaveObject(obj));
await transaction.HashSetAsync(emailKey, new[] { new HashEntry(obj.Email, Convert.ToString(obj.ID)) });
return await transaction.ExecuteAsync();
Commands executed inside a transaction do not return results until after you execute the transaction. This is simply a feature of how transactions work in Redis. At the moment you are awaiting something that hasn't even been sent yet (transactions are buffered locally until executed) - but even if it had been sent: results simply aren't available until the transaction completes.
If you want the result, you should store (not await) the task, and await it after the execute:
var fooTask = tran.SomeCommandAsync(...);
if(await tran.ExecuteAsync()) {
var foo = await fooTask;
}
Note that this is cheaper than it looks: when the transaction executes, the nested tasks get their results at the same time - and await handles that scenario efficiently.
Marc's answer works, but in my case it caused a decent amount of code bloat (and it's easy to forget to do it this way), so I came up with an abstraction that sort of enforces the pattern.
Here's how you use it:
await db.TransactAsync(commands => commands
.Enqueue(tran => tran.SomeCommandAsync(...))
.Enqueue(tran => tran.SomeCommandAsync(...))
.Enqueue(tran => tran.SomeCommandAsync(...)));
Here's the implementation:
public static class RedisExtensions
{
public static async Task TransactAsync(this IDatabase db, Action<RedisCommandQueue> addCommands)
{
var tran = db.CreateTransaction();
var q = new RedisCommandQueue(tran);
addCommands(q);
if (await tran.ExecuteAsync())
await q.CompleteAsync();
}
}
public class RedisCommandQueue
{
private readonly ITransaction _tran;
private readonly IList<Task> _tasks = new List<Task>();
public RedisCommandQueue Enqueue(Func<ITransaction, Task> cmd)
{
_tasks.Add(cmd(_tran));
return this;
}
internal RedisCommandQueue(ITransaction tran) => _tran = tran;
internal Task CompleteAsync() => Task.WhenAll(_tasks);
}
One caveat: This doesn't provide an easy way to get at the result of any of the commands. In my case (and the OP's) that's ok - I'm always using transactions for a series of writes. I found this really helped trim down my code, and by only exposing tran inside Enqueue (which requires you to return a Task), I'm less likely to "forget" that I shouldn't be awaiting those commands at the time I call them.
I and our team were bitten by this issue several times, so I created a simple Roslyn analyzer to spot such problems.
https://github.com/olsh/stack-exchange-redis-analyzer

async method does not continue when await statement returns

I'm using MVC 4 and I have the following code :
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}
public async Task MakeADelayAsync()
{
await Task.Delay(5000);
var generalHubContext = GlobalHost.ConnectionManager.GetHubContext<GeneralHub>();
generalHubContext.Clients.Client(connectionId).showNotification("Completed");
}
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
The problem is in the "MakeADelayAsync" method, those two lines after await won't be called ever. It seems that the flow never continues after await.
First question is Where is the problem in "MakeADelayAsync" ?
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing? I never use "a" anyway.
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
Doing this is extremely dangerous. I strongly recommend that you use a persistent queue, as I said in my previous answer: Azure queue, MSMQ, WebSphere MQ, etc.
However, if you insist on doing it the dangerous way, then you can use the code that I have on my blog to execute background work on ASP.NET outside of a request context:
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
// This is extremely dangerous code! If ASP.NET unloads
// your app, then MakeADelayAsync may not run to completion.
BackgroundTaskManager.Run(() => MakeADelayAsync());
}
First question is Where is the problem in "MakeADelayAsync" ?
You're executing code that is attempting to resume on the request context after the request is completed and the request context is disposed. It's the same problem you had before.
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing?
The compiler warning is telling you that the code is almost certainly a mistake... and the compiler is right.
can you try to mark your DoWork method as async?
public async void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}

How to check if async/await really async?

I have built a certain application( service ) based on async/await new keywords in c# 5.0 using WebApi which it self cool, I have create a call from Oracle db Http_Request, but i have tested and it's not really feels right, how can I unit test the async matter if this?
public async Task<WebResponse> Post(Customer customer)
{
if (!customer.ReturnSuccess()) throw new ArgumentNullException("customer");
_logger.Info(string.Format("Customer validation request - date = {0} \n {1}\t\n", DateTime.Now, customer));
try
{
return await Task.Factory.StartNew(() => _service.EvaluateCustomer(customer));
}
catch (Exception e)
{
_logger.ErrorException("Error", e);
}
return null;
}
Do not Unit Test language features - they are already tested by someone who has much more money than you. Test your business logic instead.
Read msdn about async/await behaviour here:
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx
The method runs synchronously until it reaches its first await
expression, at which point the method is suspended until the awaited
task is complete. In the meantime, control returns to the caller of
the method, as the example later in this topic shows.
I agree with Cheburek in general: don't waste your time unit testing things like await and Task.Run.
However, if you want to ensure your method is properly waiting for EvaluateCustomer, then you inject a service that is under your control and ensure Post only completes after EvaluateCustomer completes:
[TestMethod]
public async Task PostWaitsForEvaluateCustomer()
{
var finishEvaluateCustomer = new ManualResetEvent(false);
var service = new MyFakeService(finishEvaluateCustomer)
{
EvaluateCustomer = _ => finishEvaluateCustomer.WaitOne();
};
var objectUnderTest = new MyObject(service);
Task postTask = objectUnderTest.Post(..);
Assert.IsFalse(postTask.IsCompleted);
finishEvaluateCustomer.Set();
await postTask;
}