Avalonia采用AOT编译后无法运行解决办法

近日在制作Avalonia程序过程中,发现调试时很正常,发布后却无法运行,感觉很奇怪,我的发布配置有以下两条:

1
2
<PublishTrimmed>True</PublishTrimmed>
<PublishAot Condition="'$(Configuration)' != 'Debug'">true</PublishAot>

第一条启用了裁剪,第二条启用了AOT编译(但是在开发时没开启,因为预览窗口不支持AOT)

经过一番排查,发现这两个都有问题:

  1. 反射对AOT不友好,我的ViewLocator.cs使用了反射来创建对象
  2. 有的库对剪裁支持不好,因此要对其关闭剪裁

解决方案

问题1: 消除反射

原代码使用反射创建对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewType))
{
return (Control)Activator.CreateInstance(viewType)!; // 这里使用了反射
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}

修改后使用工厂方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Control? Build(object? param)
{
if (param != null && param is ViewModelBase)
{
var viewModelType = param.GetType();
if (_viewModelViewMappings.TryGetValue(viewModelType, out var viewFactory))
{
return viewFactory(); // 使用了工厂方法
}
return new TextBlock { Text = "Not Found: " + viewModelType.FullName };
}
return null;
}

这样就可以消除反射了

问题2: 关闭特定库的剪裁

发布时我注意到很多这样的剪裁警告

1
2
3
4
5
2>Assembly 'Serilog' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'ReactiveUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'SukiUI' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'Avalonia.Controls.DataGrid' produced AOT analysis warnings.

因此我修改项目的sln文件,增加以下片段,通过外部的xml文件来限制剪裁

1
2
3
<ItemGroup>
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>

下面是TrimmerRoots.xml的内容

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8" ?>
<linker>
<assembly fullname="Serilog" />
<assembly fullname="Serilog.Sinks.Console" />
<assembly fullname="Serilog.Sinks.File" />
<assembly fullname="ReactiveUI" />
<assembly fullname="SukiUI" />
<assembly fullname="Serilog.Sinks.File" />
</linker>

我将所有报警告的项目都加入了进去,虽然后面的编译依旧有新的警告,但是程序可以正常运行了。至此,所有问题解决。

Avalonia Unable to resolve property or method of name 'xxx' on type 'XamlX.TypeSystem.XamlPseudoType'解决办法

近期我在使用Avalonia编写桌面程序时,用到了ItemRepeater组件,写出来大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="clr-namespace:CooingOwl.ViewModels"
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
x:DataType="vm:ExploreViewModel"
x:Class="CooingOwl.Views.ExploreView">

<ScrollViewer HorizontalScrollBarVisibility="Auto">
<ItemsRepeater ItemsSource="{Binding B}" Margin="16">
<ItemsRepeater.Layout>
<StackLayout Spacing="20"
Orientation="Vertical" />
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<suki:GlassCard>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Margin="4 0" FontWeight="Bold"
Text="{Binding Id}"/>
</StackPanel>
</suki:GlassCard>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>

</UserControl>

其中<TextBlock Text="{Binding Name}"/>Text="{Binding Id}"/>产生了报错AVLN2000 Unable to resolve property or method of name 'Id' on type 'XamlX.TypeSystem.XamlPseudoType'.,查看类型ExploreViewModel,定义大概如下

1
2
3
4
5
6
7
8
9
public class ExploreViewModel : ViewModelBase
{
public A[] B { get; set; } = new A[] { ... };
}

public class A{
int Id,
string Name
}

造成该问题的原因是我需要使用的属性B是一个原始的数组,这里应该使用ObservableCollection因此解决方案是做出如下修改

1
2
3
4
public class ExploreViewModel : ViewModelBase
{
public ObservableCollection<Assistant> Assistants { get; set; } = new (new List<Assistant>{...});
}

至此能够成功编译运行