Skip to main content
All docs
V24.2
.NET 8.0+
  • The page you are viewing does not exist in the .NET Framework 4.6.2+ platform documentation. This link will take you to the parent topic of the current section.

DevExpress v24.2 Update — Your Feedback Matters

Our What's New in v24.2 webpage includes product-specific surveys. Your response to our survey questions will help us measure product satisfaction for features released in this major update and help us refine our plans for our next major release.

Take the survey Not interested

BlazorApplication.InvokeAsync(Func<Task>) Method

Namespace: DevExpress.ExpressApp.Blazor

Assembly: DevExpress.ExpressApp.Blazor.v24.2.dll

NuGet Package: DevExpress.ExpressApp.Blazor

#Declaration

public virtual Task InvokeAsync(
    Func<Task> func
)

#Parameters

Name Type Description
func Func<Task>

A delegate to invoke on Blazor’s synchronization context.

#Returns

Type Description
Task

A Task object.

#Remarks

The following code snippet demonstrates how to use this InvokeAsync method overload:

cs
using DevExpress.ExpressApp.Blazor;
// ...
await blazorApplication.InvokeAsync(async () => {
    var message = await GetMessageAsync();
    blazorApplication.ShowViewStrategy.ShowMessage(message);
});

Blazor’s synchronization context implements a single-threaded model of execution. At any point in time, only one thread can execute code. XAF Blazor relies on this model. To safely invoke XAF code, this code must be executed on Blazor’s synchronization context. Otherwise, the code will be prone to race conditions that can cause security issues, data loss, or other undesirable behavior.

#Error handling

If the delegate code throws an IUserFriendlyException, the user receives a user-friendly error notification, but the exception does not propagate to the caller method:

cs
using DevExpress.ExpressApp.Blazor;
// ...
async Task CallerMethod() {
    // Does not raise an exception.
    await blazorApplication.InvokeAsync(() => {
        // "An error occurred" message will be shown to the user.
        throw new UserFriendlyException("An error occurred");
    });
}

If any other type of exception is thrown, the user’s application instance will crash, and the exception will be rethrown at the call site:

cs
using DevExpress.ExpressApp.Blazor;
// ...
async Task CallerMethod() {
    // Raises an InvalidOperationException.
    await blazorApplication.InvokeAsync(() => {
        // Crashes the user's application instance.
        throw new InvalidOperationException();
    });
}

To avoid crashing a user’s application, wrap the delegate code with a try-catch block and handle the exceptions in the desired manner.

#Execution context

When your code calls InvokeAsync, XAF temporarily restores the ExecutionContext associated with a BlazorApplication instance. This restoration has the following implications:

  • ValueManager can access data stored by the application.
  • Localized messages are displayed in the user’s selected language.
  • AsyncLocal<T> values are restored to the state they were in when ExecutionContext was captured:

    cs
    using System;
    using DevExpress.ExpressApp.Blazor;
    // ...
    static AsyncLocal<string> AsyncLocal { get; } = new();
    async Task CallerMethod() {
        AsyncLocal.Value = "not null";
        await blazorApplication.InvokeAsync(() => {
            Console.WriteLine(AsyncLocal.Value ?? "null"); // Prints `null`.
        });
    }
    

#Pitfalls

While Blazor’s synchronization context guarantees single-threaded code execution, the order of operations is not guaranteed. Consider the following situation:

cs
using DevExpress.ExpressApp.Blazor;
// ...
if (View.CurrentObject is Order order) {
    var newDeliveryDate = await OrderTrackingService.CalculateDeliveryDate(order);
    order.DeliveryDate = newDeliveryDate; // May throw an `ObjectDisposedException`.
}

The user may navigate away from the current View before the new delivery date is assigned to the order object. In this case, the assignment statement fails with an ObjectDisposedException.

To avoid similar issues, validate the application state across await points. You can also use APIs such as TaskCompletionSource and CancellationTokenSource to signal when an asynchronous operation should proceed or be canceled.

See Also