0Pricing
C# Academy · Lektion

ConfigureAwait und SynchronizationContext

Verstehen Sie SynchronizationContext, verwenden Sie ConfigureAwait(false) in Bibliothekscode und vermeiden Sie Deadlocks in asynchronen Abläufen.

ConfigureAwait und SynchronizationContext ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist SynchronizationContext?

SynchronizationContext steuert, wie Fortsetzungscode nach einem await eingeplant wird. In UI-Anwendungen (WPF, WinForms) stellt er sicher, dass UI-Aktualisierungen im UI-Thread ausgeführt werden. In ASP.NET Core gibt es keinen SynchronizationContext (er wurde entfernt). Dieses Verständnis ist entscheidend, um korrekten asynchronen Code zu schreiben.

Funktionsweise von ConfigureAwait

.ConfigureAwait(false) weist den Awaiter an, den aktuellen SynchronizationContext NICHT zu erfassen und die Ausführung dort fortzusetzen. Die Fortsetzung läuft stattdessen auf einem beliebigen verfügbaren Threadpool-Thread.

// Default: captures context (resumes on original context)
var data = await FetchDataAsync();
UpdateUI(data); // runs on UI thread — correct for UI apps

// ConfigureAwait(false): doesn't capture context
var data2 = await FetchDataAsync().ConfigureAwait(false);
// Runs on any thread — DON'T access UI thread-only objects here

Das klassische Deadlock-Muster

Das Blockieren einer Task mit .Result oder .Wait(), während ein Synchronisierungskontext aktiv ist, verursacht einen klassischen Deadlock: Die Fortsetzung wartet auf den Kontext, der seinerseits darauf wartet, dass die Fortsetzung abgeschlossen wird.

// DEADLOCK in WPF/WinForms or ASP.NET classic:
string result = GetDataAsync().Result; // blocks UI thread
// GetDataAsync() tries to resume on UI thread after await
// UI thread is blocked by .Result
// DEADLOCK!

// Fix 1: await properly (never block)
string result = await GetDataAsync();

// Fix 2: use ConfigureAwait(false) in the library
public async Task<string> GetDataAsync()
    => await client.GetStringAsync(url).ConfigureAwait(false);

ConfigureAwait(false) in Bibliotheken

Bibliothekscode, der kontextunabhängig ist, sollte bei jedem await immer ConfigureAwait(false) verwenden. Dadurch werden Deadlocks verhindert, wenn Aufrufer die Bibliothek aus einer kontextabhängigen Umgebung verwenden.

// Library code — always ConfigureAwait(false)
public async Task<User?> GetUserAsync(int id)
{
    var json = await client
        .GetStringAsync($"/users/{id}")
        .ConfigureAwait(false);

    var user = JsonSerializer.Deserialize<User>(json);
    return user;
}

// Application code (has context) — leave ConfigureAwait default
public async Task LoadUserProfileAsync(int id)
{
    var user = await userService.GetUserAsync(id); // context captured
    ProfileLabel.Text = user?.Name; // safe to update UI
}

ASP.NET Core: Kein SynchronizationContext

ASP.NET Core verfügt absichtlich über keinen SynchronizationContext. Fortsetzungen laufen auf dem Threadpool. ConfigureAwait(false) ist technisch ein No-op, bleibt aber eine gute Gewohnheit für Code, der mit anderen Frameworks gemeinsam genutzt wird.

// In ASP.NET Core, both are equivalent:
var data = await service.GetAsync();                      // fine
var data2 = await service.GetAsync().ConfigureAwait(false); // also fine

// Context-free means: no deadlock risk from .Result in ASP.NET Core
// BUT: mixing with libraries that assume a context is still risky
// BEST PRACTICE: still use ConfigureAwait(false) in library code

Threadpool- gegenüber Kontextplanung

Ohne Kontext werden Fortsetzungen vom TaskScheduler geplant, normalerweise vom ThreadPoolTaskScheduler. Mit einem UI-Kontext werden sie an die UI-Nachrichtenschleife gesendet.

// Check current synchronization context:
Console.WriteLine(SynchronizationContext.Current?.GetType().Name
    ?? "No context (thread pool)");

// In a WPF event handler: "DispatcherSynchronizationContext"
// In ASP.NET Core: null (no context)
// In a unit test with xUnit: "AsyncTestSyncContext"

// After ConfigureAwait(false):
await Task.Delay(1).ConfigureAwait(false);
Console.WriteLine(SynchronizationContext.Current?.GetType().Name
    ?? "No context"); // null — context was abandoned

ConfigureAwait in Schleifen

Beim Warten in einer Schleife läuft die Fortsetzung jeder Iteration im erfassten Kontext, sofern nicht ConfigureAwait(false) verwendet wird. Verwenden Sie es in Bibliothekscode konsistent bei jedem await innerhalb der Schleife.

// Library loop: ConfigureAwait(false) on every await
public async Task ProcessBatchAsync(IEnumerable<int> ids)
{
    foreach (var id in ids)
    {
        var item = await FetchItemAsync(id).ConfigureAwait(false);
        await SaveItemAsync(item).ConfigureAwait(false);
    }
}

ValueTask und ConfigureAwait

ValueTask unterstützt ebenfalls ConfigureAwait(false). Wenden Sie es nach denselben Regeln wie bei Task konsistent an.

public async ValueTask<string> GetFromCacheAsync(string key)
{
    // ValueTask with ConfigureAwait(false)
    var raw = await _store.GetAsync(key).ConfigureAwait(false);
    return raw ?? "";
}

Task.Run zum Vermeiden des Kontexts

Verwenden Sie Task.Run, um CPU-intensive Arbeit auf den Threadpool auszulagern und sicherzustellen, dass sie niemals auf einem Thread mit Kontext, etwa dem UI-Thread, ausgeführt wird.

// WRONG in UI app: blocks UI thread
void ButtonClick(object? sender, EventArgs e)
{
    var result = HeavyComputation(); // blocks UI
    Label.Text = result;
}

// CORRECT: offload to thread pool
async void ButtonClick(object? sender, EventArgs e)
{
    var result = await Task.Run(() => HeavyComputation());
    // Continuation captured UI context: safe to update UI
    Label.Text = result;
}

Praxisbeispiel: HttpClient-Bibliothek mit ConfigureAwait

Ein HTTP-Client-Wrapper für den Produktiveinsatz verwendet durchgehend ConfigureAwait(false), damit er aus jedem Kontext sicher aufgerufen werden kann.

public class ApiClient
{
    private readonly HttpClient _http;
    private readonly JsonSerializerOptions _opts = new(JsonSerializerDefaults.Web);

    public ApiClient(HttpClient http) => _http = http;

    public async Task<T> GetAsync<T>(string path, CancellationToken ct = default)
    {
        using var response = await _http
            .GetAsync(path, ct)
            .ConfigureAwait(false);

        response.EnsureSuccessStatusCode();

        return await response.Content
            .ReadFromJsonAsync<T>(_opts, ct)
            .ConfigureAwait(false)
            ?? throw new InvalidOperationException("Null response");
    }
}

Kurztest

Warum verursacht der Aufruf von .Result für eine Task in einer WPF- oder WinForms-Anwendung häufig einen Deadlock?

Zusammenfassung: ConfigureAwait und SynchronizationContext

Wichtige Erkenntnisse:

  • SynchronizationContext: plant Fortsetzungen zurück auf einem bestimmten Thread, etwa dem UI-Thread
  • ConfigureAwait(false): verwirft die Kontexterfassung und setzt die Ausführung auf dem Threadpool fort
  • Bibliothekscode: Verwenden Sie immer ConfigureAwait(false), um Deadlocks zu verhindern
  • Anwendungscode mit UI: Verwenden Sie das standardmäßige await, um zum UI-Thread zurückzukehren
  • ASP.NET Core: kein SynchronizationContext – für gemeinsam genutzte Bibliotheken ist es dennoch eine gute Praxis
  • Blockieren Sie in kontextabhängigen Anwendungen niemals eine Task mit .Result/.Wait()

Häufig gestellte Fragen

Ist die Lektion „ConfigureAwait und SynchronizationContext“ kostenlos?

Ja — der vollständige Text von „ConfigureAwait und SynchronizationContext“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „ConfigureAwait und SynchronizationContext“?

Verstehen Sie SynchronizationContext, verwenden Sie ConfigureAwait(false) in Bibliothekscode und vermeiden Sie Deadlocks in asynchronen Abläufen. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „ConfigureAwait und SynchronizationContext“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. IAsyncEnumerable und await foreach
  2. System.Threading.Channels
  3. ValueTask und Vermeidung von Allokationen
  4. ConfigureAwait und SynchronizationContext
← Zurück zu C# Academy