# Working with async/await in .Net 4.8

`await` waits for the completion of an asynchronous operation and directly catches any errors that occur during this process. This ensures that you don’t overlook exceptions.

If you only assign the task to a variable and do not await it e.g., `_ = DoSomethingAsync()`Exceptions from the operation may go unobserved, potentially resulting in an `UnobservedTaskException`.

To make your code more robust and resilient to errors, it is recommended to use `await`. Even in fire-and-forget scenarios, logging background exceptions is important for debugging and stability.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">All asynchronous operations defined using RegisterAsyncTask in <a target="_self" rel="noopener noreferrer nofollow" href="http://ASP.NET" style="pointer-events: none">ASP.NET</a> Web Forms should also be wrapped in a try-catch block. Otherwise, Page.HandleError() is triggered, resulting in an <strong>HttpUnhandledException</strong></div>
</div>

### Where Should You Place the try/catch Block in [ASP.NET](http://ASP.NET) Web Forms?

When working with asynchronous methods in [ASP.NET](http://ASP.NET) Web Forms, particularly when using `Page.RegisterAsyncTask`, **the safest and most reliable approach is to place your** `try/catch` block *inside the async method itself* — not where it is registered or called.

```csharp
protected void btnSMS_Click(object sender, EventArgs e)
{
    Page.RegisterAsyncTask(new PageAsyncTask(SendSMSHandler));
}

private async Task SendSMSHandler()
{
    try
    {
        await GridSMS();
    }
    catch (Exception ex)
    {
        await PublicFunctions.SendMailAsync();
    }
}
```

Here’s why this structure is important:

* The `RegisterAsyncTask` method only **schedules** the async task to be executed later in the page lifecycle.
    
* If an exception occurs inside `SendSMSHandler` and there's no `try/catch` within that method, it **won’t be caught at the calling level**.
    
* Instead, the unhandled exception bubbles up and is caught by [ASP.NET](http://ASP.NET)'s internal error handler, resulting in a `System.Web.HttpUnhandledException`.
    

This can cause:

* A full-page crash or white screen
    
* Application pool instability
    
* In some cases, **process-level crashes** if unmanaged code is involved
    

Common Mistake – Catching Outside the Async Method

This structure is **not effective**:

```csharp
protected void btnSMS_Click(object sender, EventArgs e)
{
    try
    {
        Page.RegisterAsyncTask(new PageAsyncTask(SendSMSHandler));
    }
    catch (Exception ex)
    {
        // ❌ This will not catch exceptions inside SendSMSHandler
    }
}
```

Why? Because `RegisterAsyncTask` doesn’t *execute* the method immediately — it only *queues* it.

### Why should we use the async method?

The await keyword provides the feature that allows other processes to continue asynchronously while waiting for the task to finish its job, that is, non-blocking.

For example, when you make an asynchronous web service request, [ASP.NET](http://ASP.NET) will **not use threads** between the async method call and the await. It prevents thread starvation.

**Authoring Async Methods**

1. **async Task** MyMethod() { }  
    which creates a method that can be awaited, but does not return any value,
    
2. **async Task&lt;T&gt;** MyReturningMethod { return default(T); }  
    which creates a method that can be awaited, and returns a value of the type T,
    
3. protected void DetailsView1\_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e) { }  
    async void methods are only suited for UI event handlers
    

**Do NOT use things like** [`Task.Run`](http://Task.Run) directly instead of `RegisterAsyncTask`.  
Because doing so takes the execution out of [ASP.NET](http://ASP.NET)’s `SynchronizationContext`, which can cause issues with UI updates.

**Question:** *Must there be an* `await` inside an `async Task` method?

**Answer:** If there's no `await`, then why are you using `async`?

If you're not using `await` inside a method, there's **no point** in marking it `async`. Because: an `async` method only provides asynchronous behavior when `await` is used.  
So if there's no `await`, **don't make the method async**.

In Web Forms applications, async implementation appears in two forms:

1. When the method is declared in the HTML (e.g., `OnRowCommand="grdOrders_RowCommand"`),
    
2. When the method is **not** referenced in markup and triggered independently.
    

Let’s go through both:

### 1\. If the event is declared in HTML (e.g., `OnRowCommand="grdOrders_RowCommand"`):

[ASP.NET](http://ASP.NET) Web Forms **does not support** `async Task` event handlers in this case.  
You must use `void`.

**Method A (Recommended):**

* Preserves [ASP.NET](http://ASP.NET)'s page lifecycle.
    
* Ensures the page does **not render** until the async operation completes.
    
* Provides a safer and more manageable structure.
    

However, be aware of `NullReferenceException` when accessing controls like `TextBox`es.  
This is due to timing issues between the UI and async code execution.

**Therefore**, if you need to access values from controls (e.g., `username.Text`),  
**make sure you retrieve them before** the async method is invoked.

**Root cause:**  
Code executed via `RegisterAsyncTask` runs **after** standard page events have completed  
(typically around `PreRenderComplete`).

```csharp
protected void DetailsView1_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
    var detailsView = (DetailsView)sender;

    var isNETGSM = ((CheckBox)detailsView.FindControl("chkNETGSM"))?.Checked ?? false;

    if (isNETGSM)
    {
        var company = ((DropDownList)detailsView.FindControl("DropDownList1"))?.SelectedValue;
        var username = ((TextBox)detailsView.FindControl("txtUsername"))?.Text;
        var password = ((TextBox)detailsView.FindControl("txtPassword"))?.Text;

        Page.RegisterAsyncTask(new PageAsyncTask(async () =>
        {
            await UpdateSMSheaders(company, username, password);
        }));
    }
}
```

**Method B (Not Recommended):**

* If exceptions are not properly handled with try-catch, the app **may crash**.
    
* Managing flow within the page lifecycle is harder and riskier.
    

```csharp
protected async void DetailsView1_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
    await UpdateSMSheaders(sender);
}
```

### 2\. If the method **is not referenced in the HTML markup**,

you can safely use `Page.RegisterAsyncTask`.

**Examples:**

```csharp
protected void Page_Load(object sender, EventArgs e)
{
     Page.RegisterAsyncTask(new PageAsyncTask(MembershipHandler));
}

protected void btnUye_Click(object sender, EventArgs e)
{
    Page.RegisterAsyncTask(new PageAsyncTask(MembershipHandler));
}

private async Task MembershipHandler()
{
    await PublicFunctions.SendMailAsync();	
}
```

## ConfigureAwait

In terms of ConfigureAwait, the **default value** is ConfigureAwait(**true**). Therefore, if you don’t explicitly specify it, your code will behave as if you used ConfigureAwait(true).

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If you see ConfigureAwait(true) in the production code, you can delete it without ill effect.</div>
</div>

ConfigureAwait(false), I recommend using it for **library code** and **not application code**. If you don't write any library code then you probably won't ever have to use it.

You make simple use of await, and the right things happen with regards to callbacks/continuations being posted back to the original context if one existed. This leads to the general guidance:

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If you’re writing app-level code, <strong>do not use</strong> ConfigureAwait(false).</div>
</div>

The setting of downloadBtn.Content = text needs to be done back in the original context.

**Right usage :**

```csharp
private static readonly HttpClient s_httpClient = new HttpClient();
private async void downloadBtn_Click(object sender, RoutedEventArgs e)
{
    string text = await s_httpClient.GetStringAsync("http://example.com/currenttime");
    downloadBtn.Content = text;
}
```

**Wrong usage :**

```csharp
private static readonly HttpClient s_httpClient = new HttpClient();
private async void downloadBtn_Click(object sender, RoutedEventArgs e)
{
    string text = await s_httpClient.GetStringAsync("http://example.com/currenttime").ConfigureAwait(false); // bug
    downloadBtn.Content = text;
}
```

The same would go for code in a classic [ASP.NET](http://ASP.NET) app reliant on HttpContext.Current; using ConfigureAwait(false) and then trying to use HttpContext.Current is likely going to result in problems.

Reference :  
[https://devblogs.microsoft.com/dotnet/configureawait-faq/](https://devblogs.microsoft.com/dotnet/configureawait-faq/)

[https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html](https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html)

### WaitAll vs. WhenAll What's the difference?

Task.WaitAll() then the UI thread is blocked and the UI is never updated. If you use await Task.WhenAll() then the UI thread is not blocked, and the UI will be updated.

So;

WaitAll is a **blocking** call

When all is not. **Code will continue** executing

Use which when:

WaitAll when cannot continue without having the result

WhenAll when what just to be notified, not blocked

References :

[https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/](https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/)[https://stackoverflow.com/questions/38423472/what-is-the-difference-between-task-run-and-task-factory-startnew](https://stackoverflow.com/questions/38423472/what-is-the-difference-between-task-run-and-task-factory-startnew)[https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html](https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html)

[https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f](https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f)

[https://stackoverflow.com/questions/51491590/an-asynchronous-operation-exceeded-the-page-timeout-trying-to-use-httprequestme](https://stackoverflow.com/questions/51491590/an-asynchronous-operation-exceeded-the-page-timeout-trying-to-use-httprequestme)

[https://www.linkedin.com/pulse/should-i-use-configureawaittrue-configureawaitfalse-viswanathan/](https://www.linkedin.com/pulse/should-i-use-configureawaittrue-configureawaitfalse-viswanathan/)
