Сбой .NET MAUI в PROD

В настоящее время я разрабатываю приложение .NET MAUI, все отлично работает в режиме DEBUG, но при публикации приложения я получаю:

      System.InvalidCastException
Arg_InvalidCastException

исключение при запуске, делающее приложения для iOS и Android непригодными для использования.

Согласно трассировке стека, это связано с конструктором моих страниц,

РЕДАКТИРОВАТЬ [Лучшая трассировка стека]

      2023-02-22 09:27:14.000039-0600 Envivu[94104:520252] Unhandled managed exception: Arg_InvalidCastException (System.InvalidCastException)
   at Envivu.Buyer.Controls.Views.OnboardingItemView.InitializeComponent()
   at Envivu.Buyer.Controls.Views.OnboardingItemView..ctor()
   at Envivu.Buyer.Pages.OnboardingPage.InitializeComponent()
   at Envivu.Buyer.Pages.OnboardingPage..ctor(OnboardingVm vm)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Maui.MauiContext.WrappedServiceProvider.GetService(Type serviceType)
   at Microsoft.Maui.Controls.ShellContent.<>c__DisplayClass19_0.<Microsoft.Maui.Controls.IShellContentController.GetOrCreateContent>b__0()
   at Microsoft.Maui.Controls.ElementTemplate.CreateContent()
   at Microsoft.Maui.Controls.Internals.DataTemplateExtensions.CreateContent(DataTemplate self, Object item, BindableObject container)
   at Microsoft.Maui.Controls.ShellContent.Microsoft.Maui.Controls.IShellContentController.GetOrCreateContent()
   at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRootRenderer.LoadRenderers()
   at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRootRenderer.ViewDidLoad()
--- End of stack trace from previous location ---
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at Envivu.Buyer.Program.Main(String[] args)

но эта модель представления правильно зарегистрирована в AppShell и конструкторе приложений Maui.

       builder.Services.AddSingleton<AppShell>();

 builder.Services.AddPage<SplashScreenPage, SplashScreenVm>(shouldRegisterRoute: false);
 builder.Services.AddPage<OnboardingPage, OnboardingVm>(shouldRegisterRoute: false);

И с этим AppShell вводится в App.xaml.cs

      public App(AppShell appShell)
    {
        InitializeComponent();
        MainPage = appShell;
    }

У меня есть расширение разметки, которое делает простой расчет для изменения размера представления в соответствии с плотностью устройства, высотой и шириной экрана, я не уверен, имеет ли это какое-то отношение к этому, вызывает анимированный экран-заставку (который использует этот расширение разметки) работает нормально.

[КОД]OnnoardingPage.xaml

      <Grid Margin="0,10,0,0" RowSpacing="{mk:SizeAdapter DefaultSize=20, AttributeType=Height}">
        <Grid.RowDefinitions>
            <RowDefinition Height="{mk:SizeAdapter DefaultSize=316, AttributeType=Height}" />
            <RowDefinition Height="{mk:SizeAdapter DefaultSize=286, AttributeType=Height}" />
            <RowDefinition Height="{mk:SizeAdapter DefaultSize=10, AttributeType=Height}" />
            <RowDefinition Height="{mk:SizeAdapter DefaultSize=100, AttributeType=Height}" />
        </Grid.RowDefinitions>


        <Image
            Aspect="AspectFill"
            Grid.Row="0"
            HeightRequest="{mk:SizeAdapter DefaultSize=316,
                                           AttributeType=Height}"
            Source="onboard_image_0.png" />

        <Grid ColumnSpacing="{mk:SizeAdapter DefaultSize=10, AttributeType=Width}" Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{mk:SizeAdapter DefaultSize=20, AttributeType=Width}" />
                <ColumnDefinition Width="{mk:SizeAdapter DefaultSize=315, AttributeType=Width}" />
                <ColumnDefinition Width="{mk:SizeAdapter DefaultSize=20, AttributeType=Width}" />
            </Grid.ColumnDefinitions>

            <Border
                Background="{StaticResource White}"
                Grid.Column="0"
                HeightRequest="{mk:SizeAdapter DefaultSize=222,
                                               AttributeType=Height}"
                StrokeShape="RoundRectangle 0,20,0,20" />

            <custom:AnimatedStepper Grid.Column="1"
                                    CurrentIndex="{Binding CurrentIndex}" >
                <views:OnboardingItemView
                    ButtonText="Continuar"
                    SectionMessage="BLAH"
                    SectionTitle="BLAH TITLE" />

                <views:OnboardingItemView
                    ButtonText="Continuar"
                    SectionMessage="BLAH"
                    SectionTitle="BLAH TITLE" />

                <views:OnboardingItemView
                    ButtonText="Empezar"
                    SectionMessage="BLAH"
                    SectionTitle="BLAH TITLE" />
            </custom:AnimatedStepper>

            <Border
                Background="{StaticResource White}"
                Grid.Column="2"
                HeightRequest="{mk:SizeAdapter DefaultSize=222,
                                               AttributeType=Height}"
                StrokeShape="RoundRectangle 20,0,20,0" />

        </Grid>

        <VerticalStackLayout Grid.Row="2" Spacing="20">
            <IndicatorView HorizontalOptions="CenterAndExpand" x:Name="OnboardingIndicator">
                <IndicatorView.IndicatorTemplate>
                    <DataTemplate>
                        <BoxView CornerRadius="4" HeightRequest="8" />
                    </DataTemplate>
                </IndicatorView.IndicatorTemplate>
            </IndicatorView>

            <Button
                BackgroundColor="{StaticResource Senary}"
                Command="{Binding ForwardCommand}"
                HorizontalOptions="Center"
                Text="Saltar"
                TextColor="{StaticResource White}"
                VerticalOptions="Center"
                WidthRequest="{mk:SizeAdapter DefaultSize=120,
                                              AttributeType=Width}" />
        </VerticalStackLayout>
    </Grid>

OnboardinVm.cs

      public partial class OnboardingVm : BaseViewModel
{
    private object _lock = new object();

    [ObservableProperty] private int _currentIndex;

    public OnboardingVm(
        INavigationService navigation,
        ISessionService session,
        IIdentityService identity,
        ILoggerService logger,
        IAlertService notification)
        : base(navigation, session, identity, logger, notification)
    {

    }

    [RelayCommand]
    private Task GoNext()
    {
        lock (_lock)
        {
            if (CurrentIndex >= 2) return Forward();
            CurrentIndex++;
            return Task.CompletedTask;
        }
    }

    [RelayCommand]
    private Task Forward()
    {
        Session.HasPassedOnboarding = true;
        return Navigation.NavigateToRoot("LoginSelection");
    }
}

OnboardingItemView.xaml

      <Grid>
        <Border Background="{StaticResource White}" Stroke="{StaticResource White}">
            <Border.StrokeShape>
                <RoundRectangle CornerRadius="{mk:SizeAdapter DefaultSize=20, AttributeType=BorderRadius}" />
            </Border.StrokeShape>
        </Border>

        <Grid Margin="20" RowSpacing="{mk:SizeAdapter DefaultSize=10, AttributeType=Height}">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="{mk:SizeAdapter DefaultSize=50, AttributeType=Height}" />
            </Grid.RowDefinitions>

            <Label
                FontAttributes="Bold"
                FontSize="{mk:SizeAdapter DefaultSize=30,
                                          AttributeType=Height}"
                Grid.Row="0"
                HorizontalTextAlignment="Center"
                Text="{Binding SectionTitle, Source={x:Reference OnboardItem}}"
                TextColor="{StaticResource Black}" />
            <Label
                FontSize="{mk:SizeAdapter DefaultSize=18,
                                          AttributeType=Height}"
                Grid.Row="1"
                HorizontalTextAlignment="Center"
                Text="{Binding SectionMessage, Source={x:Reference OnboardItem}}"
                TextColor="{StaticResource Black}" />
            <Button
                BackgroundColor="{StaticResource Primary}"
                Command="{Binding GoNextCommand}"
                Grid.Row="2"
                Style="{StaticResource NormalButton}"
                Text="{Binding ButtonText, Source={x:Reference OnboardItem}}"
                TextColor="{StaticResource White}"
                WidthRequest="{mk:SizeAdapter DefaultSize=238,
                                              AttributeType=Width}" />
        </Grid>

    </Grid>

OnboardingItemView.xaml.cs

      public partial class OnboardingItemView : ContentView
{

    public static readonly BindableProperty SectionTitleProperty =
            BindableProperty.Create(nameof(SectionTitle), typeof(string), typeof(OnboardingItemView), string.Empty);

    public string SectionTitle
    {
        get => (string)GetValue(SectionTitleProperty);
        set => SetValue(SectionTitleProperty, value);
    }

    public static readonly BindableProperty SectionMessageProperty =
            BindableProperty.Create(nameof(SectionMessage), typeof(string), typeof(OnboardingItemView), string.Empty);

    public string SectionMessage
    {
        get => (string)GetValue(SectionMessageProperty);
        set => SetValue(SectionMessageProperty, value);
    }

    public static readonly BindableProperty ButtonTextProperty =
            BindableProperty.Create(nameof(ButtonText), typeof(string), typeof(OnboardingItemView), string.Empty);

    public string ButtonText
    {
        get => (string)GetValue(ButtonTextProperty);
        set => SetValue(ButtonTextProperty, value);
    }

    public OnboardingItemView()
    {
        InitializeComponent();
    }
}

Это пример того, как адаптер размера MarkupExtension работает для высоты:

      private double GetProportionateScreenHeight(double inputHeight)
    {
        var displayInfo = DeviceDisplay.MainDisplayInfo;

        var displayHeight = displayInfo.Height / displayInfo.Density;

        var rawNewHeight = (inputHeight / 812.0) * displayHeight;

        return Math.Round(rawNewHeight,0);
    }

Любая идея будет высоко оценена.

1 ответ

В моем случае точно такое же исключение было вызвано специальным расширением разметки XAML, которое реализовало IMarkupExtension, но не IMarkupExtension (универсальная версия). Еще один день отладки потрачен на разделение пополам.

Другие вопросы по тегам