fgilde/MudBlazor.Extensions

[Bug]: Dialogs Stop Working on 2nd client

Closed this issue · 10 comments

Contact Details

No response

What happened?

With Blazor server, when I try to use the same dialog across 2 different browser sessions, the dialog on the first browser session fails to load after the second session is used. If I refresh the first session, then that one can use the dialogs and now the second session cant. In 1.7.34 it's throwing the below error, but in 1.7.63 an error is never thrown, but the dialog never loads.

Microsoft.JSInterop.JSException: 'Cannot read properties of null (reading 'querySelector')
TypeError: Cannot read properties of null (reading 'querySelector')
    at new MudBlazorExtensionHelper (https://localhost:7030/_content/MudBlazor.Extensions/MudBlazor.Extensions.lib.module.js:1:4120)
    at Object.setNextDialogOptions (https://localhost:7030/_content/MudBlazor.Extensions/MudBlazor.Extensions.lib.module.js:1:10276)
    at https://localhost:7030/_framework/blazor.server.js:1:3501
    at new Promise (<anonymous>)
    at kt.beginInvokeJSFromDotNet (https://localhost:7030/_framework/blazor.server.js:1:3475)
    at https://localhost:7030/_framework/blazor.server.js:1:72077
    at Array.forEach (<anonymous>)
    at kt._invokeClientMethod (https://localhost:7030/_framework/blazor.server.js:1:72063)
    at kt._processIncomingData (https://localhost:7030/_framework/blazor.server.js:1:70105)
    at connection.onreceive (https://localhost:7030/_framework/blazor.server.js:1:64508)'

Here's the code to spawn the dialog:

<MudButton Class="d-flex align-center justify-center mud-width-full mud-paper mud-elevation-1 pa-4" @onclick="@(() => _dialogService.OpenFullScreenDialog<EnrolleeDialogList>(DialogPosition.BottomCenter, SharedDialogParameters))">

public static async void OpenFullScreenDialog<TDialogType>(
            this IDialogService _dialogService,
            DialogPosition destinationPosition,
            DialogParameters dialogParameters = null,
            Action<DialogResult> callback = null) where TDialogType : ComponentBase
        {
            var options = new DialogOptionsEx
            {
                MaximizeButton = false,
                CloseButton = false,
                //NoHeader = true,
                Resizeable = false,
                Position = destinationPosition,
                Animations = new AnimationType[] { AnimationType.Slide },
                AnimationDuration = TimeSpan.FromMilliseconds(500),
                FullScreen = true,
                FullWidth = true,
                FullHeight = true,
                DisablePositionMargin = true,
                DisableSizeMarginY = true,
                DisableSizeMarginX = true
            };

            if (dialogParameters == null)
            {
                dialogParameters = new DialogParameters();
            }

            var dialog = await _dialogService.ShowEx<TDialogType>(string.Empty, dialogParameters, options);
            if (callback != null)
            {
                callback(await dialog.Result);
            }
        }

Expected Behavior

The dialog should appear no matter how many sessions try to use it

Screenshots

No response

What browser are you using?

Chrome

Sample Solution

No response

Pull Request

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct
fgilde commented

I've fixed the problem. It will released in 1.7.64 but I havnt released it yet. But you can test it currently in the preview package 1.7.64-d2307221851

Please notice also that you need to call app.UseMudExtensions(); to use the MudBlazorExtensionsMiddleware in your Startup or Program.cs.

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<LocalStorageService>();
builder.Services.AddMudServicesWithExtensions();
builder.Services.AddMudMarkdownServices();
//builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped(sp => new HttpClient { });

MySimpleTypeRegistrations.RegisterRenderDefaults();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseMudExtensions(); // REQUIRED
app.UseStaticFiles();

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();
fgilde commented

@Dodecadaemon can you please check both version the current release 1.7.63 and the preview 1.7.64-d2307221851 please? I think I made a mistake and 1.7.63 should already work for you if you have added app.UseMudExtensions();

The issue persists in both 1.7.63 and 1.7.64-d2307221851 even with app.UseMudExtensions(); added. It's exhibiting the same behavior as before, where there's no error and no dialog.

When clicking a button to pop a dialog, the mud-overlay-dialog div is appearing in preparation for the dialog, but it never comes (this happened before too). Could it be an issue with the animations? I've tried nulling those out but it looks to fallback to default. Here's my program.cs in case that helps:

public static void Main(string[] args)
{
	var builder = WebApplication.CreateBuilder(args);

	// Add services to the container.
	var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
	
	builder.Services.AddDbContextFactory<ApplicationDbContext>(options =>
		options.UseSqlServer(connectionString));
	builder.Services.AddDatabaseDeveloperPageExceptionFilter();
	builder.Services.AddIdentity<ApplicationUserModel, ApplicationRoleModel>(options => options.SignIn.RequireConfirmedAccount = true)
		.AddEntityFrameworkStores<ApplicationDbContext>()
		.AddDefaultTokenProviders();
	builder.Services.AddRazorPages();
	builder.Services.AddServerSideBlazor();
	builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<ApplicationUserModel>>();
	// App Services
	builder.Services.AddScoped<IEmailSender, ApplicationEmailSender>();
	// Data Services
	builder.Services.AddScoped<IClaimsTransformation, UserInfoClaims>();
	builder.Services.AddMudServices();
	builder.Services.AddMudExtensions();

	builder.Services.AddAuthorization(options =>
	{
		options.AddPolicy("AccessHasntExpired", policy => policy.RequireClaim("AccessHasntExpired"));
	});

	var app = builder.Build();

	// Configure the HTTP request pipeline.
	if (app.Environment.IsDevelopment())
	{
		app.UseMigrationsEndPoint();
	}
	else
	{
		app.UseExceptionHandler("/Error");
		// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
		app.UseHsts();
	}

	app.UseHttpsRedirection();
	app.UseMudExtensions();
	app.UseStaticFiles();

	app.UseRouting();

	app.UseAuthentication();
	app.UseAuthorization();

	app.MapControllers();
	app.MapBlazorHub();
	app.MapFallbackToPage("/_Host");

	app.Run();
}
fgilde commented

Problem is Circuit handling for server side apps in combination with the reference to IJSRuntime. I try to fix it, and maybe have a solution but need then a FrameworkReference what means then my lib is not compatible with both and i need to create a extra package what I dont want.
Just to workaround your problem it should work if you inject the IJSRuntime in you dependend component or page or whatever and pass the IJSRuntime in every DialogOptionsEx where you open a dialog.

That's unfortunate, I hope you're able to resolve that issue.

As for the workaround you suggest, I can't seem to get that to work either. I've removed the IJSRuntime from my _MainLayout and moved it to the page. I'm initializing the extension each time the button is pressed, which still works on a single client, but still fails on the 2nd. Here's the relevant code in case I'm doing something wrong.

On my razor page:

@inject IJSRuntime JsRuntime;
...
<MudButton Class="d-flex align-center justify-center mud-width-full mud-paper mud-elevation-1 pa-4" OnClick="OpenUserList">
...
private async Task OpenUserList()
{
    await JsRuntime.InitializeMudBlazorExtensionsAsync(true);
    _dialogService.OpenFullScreenDialog<UserDialogList>(DialogPosition.BottomCenter, JsRuntime, SharedDialogParameters);
}

In my extension method:

public static async void OpenFullScreenDialog<TDialogType>(
    this IDialogService _dialogService,
    DialogPosition destinationPosition,
    IJSRuntime jsRuntime,
    DialogParameters dialogParameters = null,
    Action<DialogResult> callback = null) where TDialogType : ComponentBase
{
    var options = new DialogOptionsEx
    {
        MaximizeButton = false,
        CloseButton = false,
        //NoHeader = true,
        Resizeable = false,
        Position = destinationPosition,
        Animations = new AnimationType[] { AnimationType.Slide },
        AnimationDuration = TimeSpan.FromMilliseconds(500),
        FullScreen = true,
        FullWidth = true,
        FullHeight = true,
        DisablePositionMargin = true,
        DisableSizeMarginY = true,
        DisableSizeMarginX = true,
        JsRuntime = jsRuntime
    };

    if (dialogParameters == null)
    {
        dialogParameters = new DialogParameters();
    }

    var dialog = await _dialogService.ShowEx<TDialogType>(string.Empty, dialogParameters, options);
    if (callback != null)
    {
        callback(await dialog.Result);
    }
}
fgilde commented

Mm Strange on my Test the workaround helps.
However I will fix it and working on this already.
Currently not sure what's the best way. Maybe I create a own idialogservice that then implements the original to remove static extension methods. Or maybe a small separate component you can add and n the Lay-out to just control the js injection.

fgilde commented

@Dodecadaemon Can you do me a favor? can you please test if it works with 1.7.64-d2307281652.. in my tests it works now but please notice you should clear browser cache and notice its currently in a seperate branch and only available in this paackage 1.7.64-d2307281652.

Good news, that did the trick! Thank you for looking into this so quickly.

fgilde commented

Good to hear. You're welcome. Thank you very much for reporting this issue. I need to clean something's up and will release the 64 next week.

fgilde commented

Fixed in 1.7.64