- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
站长接触 AOT 已有 3 个月之久,此前在《好消息:NET 9 X86 AOT的突破 - 支持老旧Win7与XP环境》一文中就有所提及。在这段时间里,站长使用 Avalonia 开发的项目也成功完成了 AOT 发布测试。然而,这一过程并非一帆风顺。站长在项目功能完成大半部分才开始进行 AOT 测试,期间遭遇了不少问题,可谓是 “踩坑无数”。为了方便日后回顾,也为了给广大读者提供参考,在此将这段经历进行总结.
.NET AOT是将.NET代码提前编译为本机代码的技术。其优势众多,启动速度快,减少运行时资源占用,还提高安全性。AOT发布后无需再安装.NET运行时等依赖。.NET 8、9 AOT发布后,可在XP、Win7非SP1操作系统下运行。这使得应用部署更便捷,能适应更多老旧系统环境,为开发者拓展了应用场景,在性能提升的同时,也增加了系统兼容性,让.NET应用的开发和部署更具灵活性和广泛性,给用户带来更好的体验.
从项目创建伊始,就应养成良好的习惯,即只要添加了新功能或使用了较新的语法,就及时进行 AOT 发布测试。否则,问题积累到后期,解决起来会异常艰难,站长就因前期忽视了这一点,付出了惨痛的代价。无奈的解决方法是重新创建项目,然后逐个还原功能并进行 AOT 测试。经过了一周的加班AOT测试,每个 AOT 发布过程大致如下:
经过一周的努力,项目 AOT 后功能测试终于正常,至此收工.
在主工程创建一个XML文件,例如Roots.xml,内容大致如下:
<linker>
<assembly fullname="CodeWF.Toolbox.Desktop" preserve="All" />
</linker>
需要支持AOT的工程,在该XML中添加一个assembly节点,fullname是程序集名称,CodeWF.Toolbox.Desktop是站长小工具的主工程名,点击查看源码.
在主工程添加ItemGroup节点关联该XML文件:
<ItemGroup>
<TrimmerRootDescriptor Include="Roots.xml" />
</ItemGroup>
站长使用了Prism框架及DryIOC容器,若要支持 AOT,需要添加以下 NuGet 包:
<PackageReference Include="Prism.Avalonia" Version="8.1.97.11073" />
<PackageReference Include="Prism.DryIoc.Avalonia" Version="8.1.97.11073" />
rd.xml需要添加 。
<assembly fullname="Prism" preserve="All" />
<assembly fullname="DryIoc" preserve="All" />
<assembly fullname="Prism.Avalonia" preserve="All" />
<assembly fullname="Prism.DryIoc.Avalonia" preserve="All" />
在.NET Core中使用System.Configuration.ConfigurationManager包操作App.config文件,rd.xml需添加如下内容:
<assembly fullname="System.Configuration.ConfigurationManager" preserve="All" />
使用Assembly.GetEntryAssembly().location失败,目前使用ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)获取的应用程序程序配置,指定路径的方式后续再研究.
rd.xml添加如下内容:
<assembly fullname="System.Net.Http" preserve="All" />
Dapper的AOT支持需要安装Dapper.AOT包,rd.xml添加如下内容:
<assembly fullname="Dapper" preserve="All" />
<assembly fullname="Dapper.AOT" preserve="All" />
数据库操作的方法需要添加DapperAOT特性,举例如下:
[DapperAot]
public static bool EnsureTableIsCreated()
{
try
{
using var connection = new SqliteConnection(DBConst.DBConnectionString);
connection.Open();
const string sql = $@"
CREATE TABLE IF NOT EXISTS {nameof(JsonPrettifyEntity)}(
{nameof(JsonPrettifyEntity.IsSortKey)} Bool,
{nameof(JsonPrettifyEntity.IndentSize)} INTEGER
)";
using var command = new SqliteCommand(sql, connection);
return command.ExecuteNonQuery() > 0;
}
catch (Exception ex)
{
return false;
}
}
参考JsonExtensions.cs 。
序列化 。
public static bool ToJson<T>(this T obj, out string? json, out string? errorMsg)
{
if (obj == null)
{
json = default;
errorMsg = "Please provide object";
return false;
}
var options = new JsonSerializerOptions()
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};
try
{
json = JsonSerializer.Serialize(obj, options);
errorMsg = default;
return true;
}
catch (Exception ex)
{
json = default;
errorMsg = ex.Message;
return false;
}
}
反序列化 。
public static bool FromJson<T>(this string? json, out T? obj, out string? errorMsg)
{
if (string.IsNullOrWhiteSpace(json))
{
obj = default;
errorMsg = "Please provide json string";
return false;
}
try
{
var options = new JsonSerializerOptions()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};
obj = JsonSerializer.Deserialize<T>(json!, options);
errorMsg = default;
return true;
}
catch (Exception ex)
{
obj = default;
errorMsg = ex.Message;
return false;
}
}
参考项目CodeWF.NetWeaver 。
List<T>
或Dictionary<T>
实例:public static object CreateInstance(Type type)
{
var itemTypes = type.GetGenericArguments();
if (typeof(IList).IsAssignableFrom(type))
{
var lstType = typeof(List<>);
var genericType = lstType.MakeGenericType(itemTypes.First());
return Activator.CreateInstance(genericType)!;
}
else
{
var dictType = typeof(Dictionary<,>);
var genericType = dictType.MakeGenericType(itemTypes.First(), itemTypes[1]);
return Activator.CreateInstance(genericType)!;
}
}
List<T>
和Dictionary<T>
的Add
方法添加元素失败,下面是伪代码:// List<T>
var addMethod = type.GetMethod("Add");
addMethod.Invoke(obj, new[]{ child })
// Dictionary<Key, Value>
var addMethod = type.GetMethod("Add");
addMethod.Invoke(obj, new[]{ key, value })
解决办法,转换为实现的接口调用:
// List<T>
(obj as IList).Add(child);
// Dictionary<Key, Value>
(obj as IDictionary)[key] = value;
List<T>
、Dictionary<key, value>
的元素个数同上面Add方法反射获取Length或Count属性皆返回0,value.Property("Length", 0),封装的Property非AOT运行正确:
public static T Property<T>(this object obj, string propertyName, T defaultValue = default)
{
if (obj == null) throw new ArgumentNullException(nameof(obj));
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException(nameof(propertyName));
var propertyInfo = obj.GetType().GetProperty(propertyName);
if (propertyInfo == null)
{
return defaultValue;
}
var value = propertyInfo.GetValue(obj);
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch (InvalidCastException)
{
return defaultValue;
}
}
AOT成功:直接通过转换为基类型或实现的接口调用属性即可:
// 数组
var length = ((Array)value).Length;
// List<T>
if (value is IList list)
{
var count = list.Count;
}
// Dictionary<key, value>
if (value is IDictionary dictionary)
{
var count = dictionary.Count;
}
如遇AOT后无法在Windows 7运行,请添加YY-Thunks包:
<PackageReference Include="YY-Thunks" Version="1.1.4-Beta3" />
并指定目标框架为net9.0-windows.
如果第8条后还运行不了,请参考上一篇文章《.NET 9 AOT的突破 - 支持老旧Win7与XP环境 - 码界工坊 (dotnet9.com)》添加VC-LTL包,这里不赘述.
还有许多其他需要注意的地方,后续想起来逐渐完善本文.
AOT 发布测试虽然过程中可能会遇到诸多问题,但通过及时的测试和正确的配置调整,最终能够实现项目的顺利发布。希望以上总结的经验能对大家在 AOT 使用过程中有所帮助,让大家在开发过程中少走弯路,提高项目的开发效率和质量。同时,也期待大家在实践中不断探索和总结,共同推动技术的进步和发展.
AOT可参考项目:
最后此篇关于AOT使用经验总结的文章就讲到这里了,如果你想了解更多关于AOT使用经验总结的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试从 Unity 发布到我的 iPhone 4s。构建成功,但我继续收到此消息: “在 aot-only 模式下运行时无法加载 AOT 模块‘Assembly-CSharp’,因为依赖项无法找
在听说了这么多有关 Angular AOT 模式的信息后,我想尝试一下。因此,我们将应用程序迁移到 Angular v4.1.2,并进行了所有必要的更改。当我尝试使用我的 webpack 配置文件中的
我有一个 C# 项目,我需要将其编译为 native 二进制文件。我在这里读过: http://www.mono-project.com/AOT Mono 可以将程序集预编译为两个选项之一: --ao
我搜索了很多关于这种伟大语言的信息,并在此页面上找到了自己 https://github.com/dart-lang/sdk/wiki/Snapshots但它没有回答一些问题: 快照和 AOT 有什么
我知道什么是字节码检测。它只是在运行时更改 .class 文件字节码,这似乎从 JDK 1.5 开始可用。但是,据说是在类加载期间而不是运行时。 现在我的问题是,什么是 AOT 或提前检测?相反的程序
我正在为我的应用程序构建一个插件系统。我读到任何人都可以反编译 .class 文件,因此我不得不使用 Ahead-Of-Time 编译器(对吗?)。问题是我需要动态加载一些插件类。现在,我正在将所有
我的问题是 Angular 模块之一无法在 Safari 浏览器中正常工作。 我有以下代码: @NgModule({ bootstrap: [ AppComponent ], impo
我在这里问是因为我无法在网上找到完整的文档。示例 here太简单了。我有一个包含多个组件和一些模块的应用程序。用ngc编译后,我有很多错误。我发现修复它们的方法是使用相对路径。因此,我在所有组件中都使
在使用 webpack 进行 AOT 构建后,bundle 将每个组件模板包含两次,使得 bundle 比需要的大得多,因为模板作为字符串包含在内,UglifyJS 无法缩小。 我希望组件模板被排除为
我正在尝试使用 ngc 编译 angular 2.4.4: Error: Error encountered resolving symbol values statically. Expressio
当我这样做时,有什么原因(我可以解决): ngc -p tsconfig.aot.json 作为回应,它要求: 姓名: ngc 似乎忽略了我的 tsconfig.aot.json。 这可能是什么原因?
我正在开发一个 Angular 7 应用程序,除了加载问题外它工作正常,在研究中我发现我应该使用 AOT 构建而不是 JIT 或正常构建,由于应用程序规模巨大,我无法进行 aot 构建,它正在返回堆我
我在 Dynamics AX 2012 中有一个 AOT 查询,它由 HcmWorker 和 HcmEmployment 表(等等)组成。我的问题是,当我创建报告(不是 SSRS)或以其他方式使用此查
有谁知道在使用带有 AOT 编译的 Angular CLI 时如何获得更详细的错误堆栈跟踪?使用 JIT 编译运行时,我的应用程序没有问题,但是当我运行 ng build --aot 时,我得到的只是
我想查询 AOT 以查看是否存在使用 X++ 的表名。谁能指出我正确的方向或提供一些示例代码来做到这一点? 如果表存在并提供名称 (str tableName),则返回 true;否则,返回false
我有一个 Angular 5 应用程序,当我在测试模式下运行时没有问题,也就是说,当我使用 ng serve 命令在本地运行应用程序时。但是,当我在生产模式下部署应用程序时,即通过命令ng build
语境 我正在创建一个 Angular 应用程序的桌面版本,为此我正在使用 Electron 。 打开主窗口非常简单: win = new BrowserWindow({ width: 1280
我有一个看起来像这样的错误处理程序: @Injectable() export class GlobalErrorHandler implements ErrorHandler { construct
当我尝试构建启用了 AOT 选项的 Android 应用程序时,收到以下错误消息。 Invalid command line switch for "aapt.exe". VersionCode is
我在我的 Angular 2 应用程序中使用 Highcharts 和 Kendo Charts,当我尝试运行 AOT 编译时,它会抛出类似的错误 Cannot Import Module 或 Hom
我是一名优秀的程序员,十分优秀!