Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I conditionally have an "async Task" method be a no-op?

To get text written to the SQL Server XEvent profile, I have written the following method:

protected async Task LogToProfiler(string message)
{
    await using (var dbContext = await NoTrackingDbFactory.CreateDbContextAsync())
    {
        await dbContext.Database.ExecuteSqlAsync($"-- {message}");
    }
}

It works great, writing out the messages where I want to the profiler event list. The problem is, what I need is:

#if DEBUG
protected async Task LogToProfiler(string message)
{
    await using (var dbContext = await NoTrackingDbFactory.CreateDbContextAsync())
    {
        await dbContext.Database.ExecuteSqlAsync($"-- {message}");
    }
}
#else
protected void LogToProfiler(string message) {}
#end

So that in release mode there is no set up and tear down of a Task. Is there a way to do this?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Also, I do call it as:

if (profilingOn)
    await LogToProfiler("entering method");

Is this sufficient to avoid the setup/teardown if profilingOn == false? I believe it is. It’s safer to use #if DEBUG but I can force profilingOn to false if it’s built for RELEASE.

My fundamental concern is developers make mistakes and so it might end up being called even if profilingOn is false and we’re running in RELEASE mode. So I want to be as safe as possible.

>Solution :

You can just return Task.CompletedTask.

Furthermore, you can do something like this for all of the log methods:

protected async Task LogToProfiler(Func<string> messageProvider)
{
    if(!profilerEnabled) 
       return; //as you might know this section up to await will be called synchronously.
    var message = messageProvider();
    await using (var dbContext = await NoTrackingDbFactory.CreateDbContextAsync())
    {
        await dbContext.Database.ExecuteSqlAsync($"-- {message}");
    }
}

Everything up to first await in async method is invoked synchronously, on same thread. No task will be created. If you explicitly call Task.Yield() at the start of the method it will run on some other thread in pool.

Try running this:

async Task RunMe()
{
   Thread.Sleep(1000000);
}

like this:

RunMe();//no await

And you will see your main method stuck and not "fire-and-forget".

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading