Skip to content

Maui Blazor - Application initalization fails when supporting multiple timezones #23933

@tntwist

Description

@tntwist

Is there an existing issue for this?

  • I have searched the existing issues

Description

Hi there,

when supporting multiple timezones, the initalization of the abp application of Maui Blazor Apps fails.
This is the exception thrown:

An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Volo.Abp.AspNetCore.Components.MauiBlazor.AbpAspNetCoreComponentsMauiBlazorModule, Volo.Abp.AspNetCore.Components.MauiBlazor, Version=9.3.5.0, Culture=neutral, PublicKeyToken=null: Cannot invoke JavaScript outside of a WebView context.. See the inner exception for details."

Inner exception message:

"Cannot invoke JavaScript outside of a WebView context."

After some debugging I found out that the MauiBlazorCachedApplicationConfigurationClient fails while initalizing because the js runtime is invoked when multiple time zones are supported by clock. See starting from here:

Reproduction Steps

  1. Create a new abp solution using Maui Blazor as UI Framework.
  2. Support multible timezones.
  3. Start the maui blazor app.

Expected behavior

The Application should start and initalize the timezone properly, instead of failing to start.

Actual behavior

See above. Pasted stack trace there.

Regression?

I dont know.

Known Workarounds

Quirky Workaround:
Create a cached application configuration client, that overrides the `InitializeAsync``-Method and remove invokes to the jsruntime. Put the timezome initalization in some actual component, that can use the JSRuntime.

Here is an example what I did:

[Volo.Abp.DependencyInjection.Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ICachedApplicationConfigurationClient), typeof(MauiBlazorCachedApplicationConfigurationClient))]
public class MyMauiBlazorCachedApplicationConfigurationClient(
    AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy,
    ApplicationConfigurationCache cache,
    ICurrentTenantAccessor currentTenantAccessor,
    ICurrentTimezoneProvider currentTimezoneProvider,
    AuthenticationStateProvider authenticationStateProvider,
    AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy,
    ApplicationConfigurationChangedService applicationConfigurationChangedService,
    IJSRuntime jsRuntime,
    IClock clock
) : MauiBlazorCachedApplicationConfigurationClient(applicationConfigurationClientProxy, cache, currentTenantAccessor, currentTimezoneProvider, authenticationStateProvider, applicationLocalizationClientProxy, applicationConfigurationChangedService, jsRuntime, clock)
{
    public override async Task InitializeAsync()
    {
        var configurationDto = await ApplicationConfigurationClientProxy.GetAsync(
                new ApplicationConfigurationRequestOptions
                {
                    IncludeLocalizationResources = false
                }
            );

        var localizationDto = await ApplicationLocalizationClientProxy.GetAsync(
            new ApplicationLocalizationRequestDto
            {
                CultureName = configurationDto.Localization.CurrentCulture.Name,
                OnlyDynamics = true
            }
        );

        configurationDto.Localization.Resources = localizationDto.Resources;

        Cache.Set(configurationDto);

        CurrentTenantAccessor.Current = new BasicTenantInfo(
            configurationDto.CurrentTenant.Id,
            configurationDto.CurrentTenant.Name);

        ApplicationConfigurationChangedService.NotifyChanged();
    }
}

Added this to the initalization of our footer component (I know quirky but sufficient for a quick fix):

[Inject]
protected ICachedApplicationConfigurationClient ApplicationConfigurationClient { get; set; } = default!;

[Inject]
protected IJSRuntime JSRuntime { get; set; } = default!;

[Inject]
protected IClock Clock { get; set; } = default!;

[Inject]
protected ICurrentTimezoneProvider CurrentTimezoneProvider { get; set; } = default!;

private static bool _isTimezoneInitialized;

protected override async Task OnInitializedAsync()
{
    await base.OnInitializedAsync();
    await InitalizeTimeZone();
}

private async Task InitalizeTimeZone()
{
    if (!Clock.SupportsMultipleTimezone || _isTimezoneInitialized)
    {
        return;
    }

    var configuration = await ApplicationConfigurationClient.GetAsync();

    try
    {
        CurrentTimezoneProvider.TimeZone = !configuration.Timing.TimeZone.Iana.TimeZoneName.IsNullOrWhiteSpace()
            ? configuration.Timing.TimeZone.Iana.TimeZoneName
            : await JSRuntime.InvokeAsync<string>("abp.clock.getBrowserTimeZone");

        await JSRuntime.InvokeAsync<string>("abp.clock.setBrowserTimeZoneToCookie");
        _isTimezoneInitialized = true;
    }
    catch
    {
        //ignore
    }
}

Version

9.3.5

User Interface

Blazor

Database Provider

EF Core (Default)

Tiered or separate authentication server

Tiered

Operation System

Windows (Default)

Other information

No response

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions