Notes on C#
Table of Contents
ConfigureAwait(false)
What is the deal with ConfigureAwait(false)?
It determines the thread on which the code continues to execute after the await statement returns.
What does it look line?
async Task MyMethodAsync()
{
// Code here runs in the original context.
await Task.Delay(1000);
// Code here runs in the original context.
await Task.Delay(1000).ConfigureAwait(
continueOnCapturedContext: false);
// Code here runs without the original
// context (in this case, on the thread pool).
}
When should we use it?
The recommendation is to always use it in library code and not in UI/GUI code.
Why is it recommended to use in library code?
Because it is assumed that the library code will be used in different types of applications and capturing the original thread context is not important.
Why is it recommended to not use it in GUI applications?
Because capturing the SynchronizationContext is very important in GUI apps.
You do not want to do this:
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
try
{
// Can't use ConfigureAwait here ...
await Task.Delay(1000);
}
finally
{
// Because we need the context here.
button1.Enabled = true;
}
}
Any other weird detail?
ConfigureAwait configures the await not the task.
Continue Reading
ConfigureAwait(ConfigureAwaitOptions)
What is it?
It is a new flag enum.
namespace System.Threading.Tasks;
[Flags]
public enum ConfigureAwaitOptions
{
None = 0x0,
ContinueOnCapturedContext = 0x1,
SuppressThrowing = 0x2,
ForceYielding = 0x4,
}
Explain using a short example:
// These all do the same thing
await task;
await task.ConfigureAwait(continueOnCapturedContext: true);
await task.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);
// These do the same thing
await task.ConfigureAwait(continueOnCapturedContext: false);
await task.ConfigureAwait(ConfigureAwaitOptions.None);
// Default behavior (no ConfigureAwait): continue on the captured context.
await task;
// Default flag option (None): do not continue on the captured context.
await task.ConfigureAwait(ConfigureAwaitOptions.None);
// These do the same thing
await task.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
try { await task.ConfigureAwait(false); } catch { }
What is ForceYielding?
The normal behavior for await is to check if the awaitable is complete, and if it is, then continue executing synchronously; ForceYielding prevents that synchronous behavior, forcing the await to behave asynchronously.
Continue Reading
Elevating Privileges
var isElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
if (!isElevated)
{
Debug.WriteLine("Elevating Privelege");
var currentProcessPath = Environment.ProcessPath;
// In case of console application
// var currentProcessPath = Path.ChangeExtension(typeof(Program).Assembly.Location, "exe");
var processStartInfo = new ProcessStartInfo
{
UseShellExecute = true,
Verb = "runas",
FileName = currentProcessPath,
};
using var process = Process.Start(processStartInfo)
?? throw new InvalidOperationException("Could not start process.");
}