Сбой .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 (универсальная версия). Еще один день отладки потрачен на разделение пополам.