Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open Dialog from DelegatingHandler not working #484

Open
NGame1 opened this issue Nov 19, 2024 · 1 comment
Open

Open Dialog from DelegatingHandler not working #484

NGame1 opened this issue Nov 19, 2024 · 1 comment

Comments

@NGame1
Copy link

NGame1 commented Nov 19, 2024

Hi everyone,
I want to handle 401 status code globally to open a Dialog to login user.
So I tried to Add related services into my program

builder.Services.AddScoped<LoginModalService>();
builder.Services.AddScoped<AuthenticationHttpMessageHandler>();

builder.Services.AddHttpClient<IMyService, MyService>(client =>
{
    client.BaseAddress = new Uri(builder.Configuration["ApiBaseUrl"] ?? "https://localhost:7000/");
})
.AddHttpMessageHandler<AuthenticationHttpMessageHandler>();

And my AuthenticationHttpMessageHandler is simply opens a dialog

public class AuthenticationHttpMessageHandler : DelegatingHandler
{
    private readonly LoginModalService _loginModalService;

    public AuthenticationHttpMessageHandler(LoginModalService loginModalService)
    {
        _loginModalService = loginModalService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            await _loginModalService.ShowLoginModal();
        }

        return response;
    }
}

public class LoginModalService(IDialogService dialogService)
{
    private readonly IDialogService _dialogService = dialogService;

    public event Action? OnLogin;

    public async Task ShowLoginModal()
    {
        var dialog = await _dialogService.ShowAsync<TestModal>();
        var result = await dialog.Result;

        if (result?.Canceled == false)
        {
            OnLogin?.Invoke();
        }
    }
}

If I try to Inject IDialogService and Show a dialog on OnAfterRenderAsync method it simply works, but if I try to call an API and it invoke the ShowAsync in LoginModalService witch is calling from AuthenticationHttpMessageHandler it will not working.
Any workaround or fix?

My Project is .NET 8.0 and I'm using default Mudblazor Server template for my app.
dotnet new mudblazor --interactivity Server --name MyApplication --all-interactive

@ScarletKuro
Copy link
Member

Hi. This is expected since you cannot open such things from a non-UI thread. The same applies not only to Blazor but also to WPF and WinForms (an example would be if you try to call the Show method on a window).

Any workaround or fix?

You would need a long-lived Blazor component, for example, one that sits in the root of MainLayout and listens for dialog requests, possibly using a pub/sub pattern. Once it gets a notification to open a specific dialog, it simply calls _dialogService.ShowAsync inside an InvokeAsync (in other words, it queues the action on the UI thread). This is why a Blazor component is required, as only it has access to Dispatcher.InvokeAsync. Unlike WPF, there is no Application.Current.Dispatcher that can be accessed from anywhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants