When to use ConfigureAwait(true/false)

ConfigureAwait(false) is a C# feature used with async and await to control how the continuation of an async method is scheduled after an awaited operation completes.

Here’s a breakdown of when and why you might need to call ConfigureAwait(false):

Understanding Synchronization Context

  • What it is: A synchronization context (System.Threading.SynchronizationContext) represents a way to queue work (continuations) to a specific thread or threads.
    • UI Applications (WinForms, WPF, Xamarin, old ASP.NET on .NET Framework): These have a UI thread. Operations that update the UI must run on this specific UI thread. The synchronization context ensures that continuations after an await (if it wasn’t configured otherwise) are posted back to this UI thread.
    • ASP.NET Core: By default, ASP.NET Core does not have a synchronization context that behaves like the UI one. It uses a more efficient internal mechanism for managing requests.
    • Console Apps / Library Code (typically): Often have no special synchronization context, or they use the default thread pool context.
  • How await uses it: When you await a Task, by default (without ConfigureAwait(false)), the runtime captures the current SynchronizationContext (if one exists) and the current TaskScheduler. When the awaited task completes, it attempts to post the remainder of the async method (the continuation) back to that captured context or scheduler.

When You SHOULD GENERALLY Use ConfigureAwait(false)

  1. Library Code (Most Common and Important Case):
    • If you are writing a general-purpose library (e.g., a NuGet package, a shared business logic layer, a data access layer) that is not specific to any UI framework or ASP.NET Core.Reason: Your library code doesn’t know what kind of application will call it. If it’s called from an application with a restrictive synchronization context (like a UI app), and your library’s async methods always try to resume on that captured context, it can lead to:
      • Performance Issues: Unnecessary context switching back to the UI thread for non-UI work.Deadlocks: Especially if the calling code is blocking on the async method (e.g., using .Result or .Wait(), which is an anti-pattern but can happen). The UI thread might be blocked waiting for your library method to complete, while your library method is waiting to get back onto the UI thread to complete. This is a classic deadlock.
      Solution: Use ConfigureAwait(false) on all (or almost all) await calls within your library. This tells the runtime, “I don’t need to resume on the original context; any available thread pool thread is fine.”
// In a library
public async Task<string> GetDataAsync()
{
    // _httpClient is an HttpClient instance
    var response = await _httpClient.GetStringAsync("some_api_endpoint")
                                  .ConfigureAwait(false); // Don't need original context

    // Process the response (doesn't need original context)
    var processedData = Process(response); 

    await Task.Delay(100).ConfigureAwait(false); // Another example

    return processedData;
}
}

When You MIGHT NOT NEED ConfigureAwait(false) (or when ConfigureAwait(true) is implied/desired)

  1. Application-Level Code in UI Applications (e.g., event handlers, view models directly interacting with UI):
    • If the code after an await needs to interact directly with UI elements (e.g., update a label, change a button’s state).Reason: You want the continuation to run on the UI thread’s synchronization context. This is the default behavior, so explicitly using ConfigureAwait(true) is redundant but not harmful. Omitting ConfigureAwait achieves the same.
// In a UI event handler (e.g., WPF, WinForms)
private async void Button_Click(object sender, RoutedEventArgs e)
{
    MyButton.IsEnabled = false; // UI update
    var data = await _myService.FetchDataAsync(); // This service call might use ConfigureAwait(false) internally
    // The continuation here will be back on the UI thread by default
    MyLabel.Text = data; // UI update
    MyButton.IsEnabled = true; // UI update
}

  1. Application-Level Code in ASP.NET Core (e.g., Controllers, Razor Pages, Middleware):
    • Generally, not strictly needed: ASP.NET Core doesn’t have a SynchronizationContext that causes the same deadlock problems as UI frameworks or older ASP.NET. HttpContext and related services are accessible without needing to be on a specific “request thread” in the same way UI elements need the UI thread.
    • However, some developers still apply ConfigureAwait(false) out of habit or for consistency if their codebase also includes library projects where it is critical. It typically doesn’t hurt in ASP.NET Core and might offer a micro-optimization by avoiding an unnecessary check for a context.
    • If you do rely on HttpContext (e.g., HttpContext.User) after an await, ensure your understanding of its flow. In ASP.NET Core, HttpContext is generally available to continuations regardless of ConfigureAwait, but being explicit about context requirements is never a bad idea.
  2. Console Applications:
    • Usually, console applications don’t have a restrictive SynchronizationContext (they use the thread pool context). So, ConfigureAwait(false) is often not strictly necessary for preventing deadlocks.
    • However, if the console app uses libraries that might install a custom SynchronizationContext, or if you are writing code that might be reused in other contexts, using ConfigureAwait(false) can still be a good defensive measure.

Summary Table:

ContextRecommendation for ConfigureAwait(false)Reason
General-Purpose Library CodeStrongly Recommended (Use it)Prevent deadlocks, improve performance when called from context-sensitive environments (e.g., UI).
UI Application Code (Event Handlers, VMs)Generally Not Needed (Default is fine)You often need to return to the UI thread for UI updates.
ASP.NET Core Application CodeOptional / Good PracticeNo UI-like SynchronizationContext causing deadlocks. Can be a micro-optimization or for consistency.
Console Application CodeOptional / Good PracticeUsually no restrictive context, but good for reusability or if custom contexts are involved.

Export to Sheets

Key Takeaway:

The most critical place to use ConfigureAwait(false) is in library code to make it robust and performant regardless of the calling application’s environment. In application-level code, the necessity depends on whether you need to return to a specific context (like the UI thread).

As of current date (May 16, 2025), this guidance remains standard practice in the .NET ecosystem.

.NET Code Analysis with Roslyn Analyzers

NET compiler platform (Roslyn) analyzers inspect your C# or Visual Basic code for style, quality, maintainability, design, and other issues. This inspection or analysis happens during design time in all open files.

Here are the key take aways;

Maintainability index range and meaning

For the thresholds, we decided to break down this 0-100 range 80-20 to keep the noise level low and we only flagged code that was suspicious. We’ve used the following thresholds:

Index value Color Meaning
0-9 Red Low maintainability of code
10-19 Yellow Moderate maintainability of code
20-100 Green Good maintainability of code

Code metrics – Class coupling

“Module cohesion was introduced by Yourdon and Constantine as ‘how tightly bound or related the internal elements of a module are to one another’ YC79. A module has a strong cohesion if it represents exactly one task […], and all its elements contribute to this single task. They describe cohesion as an attribute of design, rather than code, and an attribute that can be used to predict reusability, maintainability, and changeability.”

The Magic Number
As with cyclomatic complexity, there is no limit that fits all organizations. However, S2010 does indicate that a limit of 9 is optimal:

“Therefore, we consider the threshold values […] as the most effective. These threshold values (for a single member) are CBO = 9[…].” (emphasis added)

Code metrics – Cyclomatic complexity

https://learn.microsoft.com/en-us/visualstudio/code-quality/code-metrics-cyclomatic-complexity?view=vs-2022

Cyclomatic complexity is defined as measuring “the amount of decision logic in a source code function” NIST235. Simply put, the more decisions that have to be made in code, the more complex it is.

The Magic Number
As with many metrics in this industry, there’s no exact cyclomatic complexity limit that fits all organizations. However, NIST235 does indicate that a limit of 10 is a good starting point:

“The precise number to use as a limit, however, remains somewhat controversial. The original limit of 10 as proposed by McCabe has significant supporting evidence, but limits as high as 15 have been used successfully as well. Limits over 10 should be reserved for projects that have several operational advantages over typical projects, for example experienced staff, formal design, a modern programming language, structured programming, code walkthroughs, and a comprehensive test plan. In other words, an organization can pick a complexity limit greater than 10, but only if it’s sure it knows what it’s doing and is willing to devote the additional testing effort required by more complex modules.” NIST235

As described by the Software Assurance Technology Center (SATC) at NASA:

“The SATC has found the most effective evaluation is a combination of size and (Cyclomatic) complexity. The modules with both a high complexity and a large size tend to have the lowest reliability. Modules with low size and high complexity are also a reliability risk because they tend to be very terse code, which is difficult to change or modify.” SATC

Putting It All Together
The bottom line is that a high complexity number means greater probability of errors with increased time to maintain and troubleshoot. Take a closer look at any functions that have a high complexity and decide whether they should be refactored to make them less complex.

Code metrics – Depth of inheritance (DIT)

Depth of Inheritance. Depth of inheritance, also called depth of inheritance tree (DIT), is defined as “the maximum length from the node to the root of the tree”.

High values for DIT mean the potential for errors is also high, low values reduce the potential for errors. High values for DIT indicate a greater potential for code reuse through inheritance, low values suggest less code reuse though inheritance to use. Due to lack of sufficient data, there is no currently accepted standard for DIT values.

You can read full article here;

https://learn.microsoft.com/en-us/visualstudio/code-quality/code-metrics-values?view=vs-2022

Add following nuget package in your project;

Microsoft.CodeAnalysis.NetAnalyzers

Integration in Azure DevOps

To integrate in Azure DevOps, follow this article;

https://secdevtools.azurewebsites.net/helpRoslynAnalyzers.html

Front-End Development Trends

When HTML was first created, it was used to present some basic formatting. You could bold certain text, you could underline certain text, etc. Later, this activity became interactive with forms. Over time, these forms became more complicated and AJAX-based tools really unleashed the possibility of what could be possible in a browser. Then, paired with the additional complexity of security and the fact that accessibility has become extremely important and essential, our plain old HTML friend started clearly showing its age. As a result, HTML had to evolve.

These days, the vast majority of new applications are served through the browser. In fact, sit back and think about it: How many new products that have been launched in the last 10 years that you use on your laptop or desktop are not web applications?

Most of these websites have some common features. They all seem to have a header, paragraphs, navigation footers, etc. For the longest time, we’ve been trying to twist tags, like div and span, with some clever CSS to act like a header, paragraphs, navigation footers, etc. Semantic HTML changes that.

Semantic HTML is a way of writing HTML that focuses on the meaning of the content rather than just its presentation. It involves using HTML elements that describe the structure and purpose of the content, making it more readable, accessible, and maintainable. Semantic HTML uses elements that provide meaning to the structure of the web page.

Semantic HTML is a standard, as defined by the World Wide Web Consortium (W3C) and maintained by the WHATWG (Web Hypertext Application Technology Working Group). The HTML specification, which includes the definition of semantic HTML elements, is a standard document that outlines the syntax, structure, and semantics of HTML. This specification is maintained by the WHATWG and is widely adopted by web browsers and other HTML parsers.

The use of semantic HTML elements, such as <header>, <nav>, <main>, <section>, <article>, <aside>, <footer>, and others, is mandated by the HTML specification. These elements provide a standardized way to define the structure and meaning of web content, making it easier for browsers, search engines, and other tools to understand and interpret the content.

Although there may be some flexibility in how semantic HTML elements are used, the specification provides clear guidelines on their usage and meaning.

Semantic HTML in practice means that instead of writing…. this article is continued online. Click here to continue.

Conditional Nested Validation with FluentValidation

This example demonstrating how to conditionally validate nested objects using FluentValidation’s When method.

Scenario

Let’s say we have:

  • Person class with an Address property
  • We only want to validate the Address when HasAddress is true
Model Classes
public class Person
{
    public string Name { get; set; }
    public bool HasAddress { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}

Validator Implementation

public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        // Always validate name
        RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
        
        // Only validate address when HasAddress is true
        When(x => x.HasAddress, () => 
        {
            RuleFor(x => x.Address)
                .NotNull()
                .WithMessage("Address must be provided when HasAddress is true");
                
            RuleFor(x => x.Address.Street)
                .NotEmpty()
                .When(x => x.Address != null)
                .WithMessage("Street is required");
                
            RuleFor(x => x.Address.City)
                .NotEmpty()
                .When(x => x.Address != null)
                .MaximumLength(50);
                
            RuleFor(x => x.Address.ZipCode)
                .NotEmpty()
                .When(x => x.Address != null)
                .Matches(@"^\d{5}(-\d{4})?$");
        });
    }
}

Alternative Approach (Using Child Validator)

public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
        
        When(x => x.HasAddress, () => 
        {
            RuleFor(x => x.Address)
                .NotNull()
                .SetValidator(new AddressValidator());
        });
    }
}

public class AddressValidator : AbstractValidator<Address>
{
    public AddressValidator()
    {
        RuleFor(x => x.Street).NotEmpty();
        RuleFor(x => x.City).NotEmpty().MaximumLength(50);
        RuleFor(x => x.ZipCode).NotEmpty().Matches(@"^\d{5}(-\d{4})?$");
    }
}

Usage Example

var person = new Person 
{
    Name = "Khan",
    HasAddress = false,
    Address = null
};

var validator = new PersonValidator();
var result = validator.Validate(person); // Won't validate address

Key Points:

  1. The When condition determines whether the nested rules should execute
  2. The nested rules are only evaluated if HasAddress is true
  3. We still need null checks for the address object itself
  4. The second approach using a separate validator is cleaner for complex nested objects

This pattern is useful when you want to validate complex objects only in certain scenarios, reducing unnecessary validation overhead.

Recommended UI Approaches for Azure AI Services Output

When displaying output from Azure AI services (like Cognitive Services, OpenAI, etc.), the UI should be tailored to the specific service and use case. Here are recommended approaches:

1. Text-Based AI Services (Language, Translation, etc.)

Recommended UI Components:

MudBlazor (for Blazor apps):

<MudPaper Elevation="3" Class="pa-4 my-4">
    <MudText Typo="Typo.h6">AI Analysis</MudText>
    <MudText>@_aiResponse</MudText>
    @if (!string.IsNullOrEmpty(_sentiment))
    {
        <MudChip Color="@(_sentiment == "Positive" ? Color.Success : 
                       _sentiment == "Negative" ? Color.Error : Color.Warning)"
                Class="mt-2">
            @_sentiment Sentiment
        </MudChip>
    }
</MudPaper>

For key phrases extraction:

<MudChipSet>
    @foreach (var phrase in _keyPhrases)
    {
        <MudChip>@phrase</MudChip>
    }
</MudChipSet>

2. Computer Vision/Image Analysis

Recommended UI:

<div style="position: relative;">
    <img src="@_imageUrl" style="max-width: 100%;" />
    @foreach (var obj in _detectedObjects)
    {
        <div style="position: absolute; 
                   left: @(obj.BoundingBox.Left * 100)%; 
                   top: @(obj.BoundingBox.Top * 100)%;
                   width: @(obj.BoundingBox.Width * 100)%;
                   height: @(obj.BoundingBox.Height * 100)%;
                   border: 2px solid red;">
            <span style="background: white; padding: 2px;">@obj.ObjectProperty</span>
        </div>
    }
</div>

3. Chat/Conversational AI (Azure OpenAI)

Recommended UI:

<MudContainer MaxWidth="MaxWidth.Medium">
    <MudPaper Elevation="3" Class="pa-4" Style="height: 60vh; overflow-y: auto;">
        @foreach (var message in _chatHistory)
        {
            <MudCard Class="my-2" Elevation="1">
                <MudCardHeader>
                    <MudAvatar>@(message.Role == "user" ? "U" : "AI")</MudAvatar>
                    <MudText Typo="Typo.subtitle2">@message.Role</MudText>
                </MudCardHeader>
                <MudCardContent>
                    <MarkdownString Value="@message.Content" />
                </MudCardContent>
            </MudCard>
        }
    </MudPaper>
    
    <MudTextField @bind-Value="_userMessage" 
                 Label="Type your message" 
                 Variant="Variant.Outlined"
                 FullWidth
                 Class="mt-4">
        <Adornment>
            <MudButton OnClick="SendMessage" 
                      Icon="@Icons.Material.Filled.Send"
                      Disabled="@_isProcessing" />
        </Adornment>
    </MudTextField>
</MudContainer>

4. Form Recognizer/Data Extraction

Recommended UI:

<MudTable Items="@_extractedData" Hover="true">
    <HeaderContent>
        <MudTh>Field</MudTh>
        <MudTh>Value</MudTh>
        <MudTh>Confidence</MudTh>
    </HeaderContent>
    <RowTemplate>
        <MudTd>@context.FieldName</MudTd>
        <MudTd>@context.Value</MudTd>
        <MudTd>
            <MudProgressLinear Value="@(context.Confidence * 100)" 
                              Color="@(context.Confidence > 0.9 ? Color.Success : 
                                     context.Confidence > 0.7 ? Color.Warning : Color.Error)"/>
        </MudTd>
    </RowTemplate>
</MudTable>

5. Custom Decision/Recommendation Services

Recommended UI:

<MudGrid>
    @foreach (var recommendation in _recommendations)
    {
        <MudItem xs="12" sm="6" md="4">
            <MudCard Elevation="5" Class="h-100">
                <MudCardHeader>
                    <MudAvatar Color="Color.Primary">@recommendation.Score.ToString("P0")</MudAvatar>
                    <MudText Typo="Typo.h6">@recommendation.Title</MudText>
                </MudCardHeader>
                <MudCardContent>
                    @recommendation.Description
                </MudCardContent>
                <MudCardActions>
                    <MudButton Variant="Variant.Text" Color="Color.Primary">View Details</MudButton>
                </MudCardActions>
            </MudCard>
        </MudItem>
    }
</MudGrid>

Best Practices for Azure AI UI

Visual Feedback:

Show loading states during API calls

<MudProgressCircular Indeterminate="true" Color="Color.Primary" 
                    Visible="@_isLoading" Class="my-4" />

Error Handling:

@if (!string.IsNullOrEmpty(_errorMessage))
{
    <MudAlert Severity="Severity.Error" Variant="Variant.Filled">
        @_errorMessage
    </MudAlert>
}

Confidence Indicators:

Visualize confidence scores for uncertain predictions

<MudTooltip Text="@($"Confidence: {_confidence:P2}")">
    <MudIcon Icon="@(_confidence > 0.9 ? Icons.Material.Filled.CheckCircle : 
                    _confidence > 0.7 ? Icons.Material.Filled.Warning : 
                    Icons.Material.Filled.Error)"
            Color="@(_confidence > 0.9 ? Color.Success : 
                   _confidence > 0.7 ? Color.Warning : Color.Error)" />
</MudTooltip>

Interactive Exploration:

Allow users to refine/correct AI outputs

<MudTextField @bind-Value="_correctedText" 
             Label="Correct the AI output"
             Visible="@_showCorrectionField" />

Responsive Design:

Ensure UI works across devices

<MudGrid>
    <MudItem xs="12" md="6">
        <!-- Input controls -->
    </MudItem>
    <MudItem xs="12" md="6">
        <!-- AI output -->
    </MudItem>
</MudGrid>

For enterprise applications, consider adding:

  • Export capabilities (PDF, CSV)
  • Audit trails of AI interactions
  • User feedback mechanisms (“Was this helpful?”)
  • Explanation components for AI decisions