尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
WPF 引用 ASP.NET Core 的 AOT 版本
WPF 引用 ASP.NET Core 的 AOT 版本引言从桌面到云端再回到桌面的新思路作为一名技术博主我经常收到这样的问题“WPF 应用能不能调用 ASP.NET Core 的 API能不能用上 AOT 编译带来的性能优势” 答案是可以而且比你想象中更简单在 .NET 生态中WPF桌面应用框架和 ASP.NET CoreWeb 框架并非孤岛它们可以通过多种方式协作。而 AOTAhead-of-Time 编译技术更是让这种协作如虎添翼——减少启动时间、降低内存占用甚至能让你在桌面应用中直接嵌入一个轻量级的 Web 服务器。本文将通过两个完整的代码示例带你一步步实现“WPF 引用 ASP.NET Core 的 AOT 版本”并在实战中理解背后的原理。## 为什么要在 WPF 中使用 ASP.NET Core AOT传统 WPF 应用与后端交互时通常需要依赖外部 Web 服务如部署在服务器上的 ASP.NET Core API。但有些场景下我们希望应用自身就具备 Web 服务能力比如- 提供本地 REST API 供其他工具调用如脚本、浏览器扩展。- 实现桌面应用内部的 IPC进程间通信时用 HTTP 比命名管道更灵活。- 利用 ASP.NET Core 强大的路由、中间件和依赖注入特性来组织本地逻辑。而 AOT 编译的优势在于-启动速度极快无需 JIT 编译代码在生成时已编译为机器码。-内存占用低不需要加载庞大的运行时 JIT 编译器。-发布体积小发布时只包含必需的代码适合嵌入式场景。但是WPF 本身是桌面框架ASP.NET Core 是 Web 框架如何将它们“合体”答案是将 ASP.NET Core 的 AOT 版本作为 WPF 项目的依赖并在 WPF 启动时内嵌一个 Web 服务器。## 环境准备与项目结构### 你需要安装- .NET 8.0 SDK 或更高版本因为 AOT 在 .NET 7 中逐步成熟.NET 8 是推荐选择。- Visual Studio 2022 或 JetBrains Rider。- 确保安装“.NET 桌面开发”和“ASP.NET 和 Web 开发”工作负载。### 项目结构建议我们将创建两个项目1.WpfAppWithAotWPF 主项目负责界面显示和启动内嵌 Web 服务器。2.AotApiLibraryASP.NET Core 类库包含 AOT 兼容的 API 端点并编译为 AOT 模式。 为什么不用一个项目因为 WPF 项目不能直接设置为 AOT 编译AOT 主要用于控制台应用或类库但我们可以将 API 逻辑封装到一个独立的 AOT 类库中然后被 WPF 引用。## 第一步创建 ASP.NET Core AOT 类库### 1. 新建类库项目使用命令行创建一个类库项目bashdotnet new classlib -n AotApiLibrary -f net8.0cd AotApiLibrary### 2. 添加必要的 NuGet 包AOT 需要特定的包来支持最小化 API 和 JSON 序列化bashdotnet add package Microsoft.AspNetCore.App.Ref --version 8.0.0dotnet add package System.Text.Json### 3. 编写 AOT 兼容的 API 代码AOT 编译需要避免使用反射和动态代码生成因此我们将使用“最小 API”风格并显式指定 JSON 序列化上下文。创建MyApi.cscsharpusing System.Text.Json.Serialization;// 定义一个简单的模型标记为 JSON 序列化上下文public class GreetingResponse{ public string Message { get; set; } public DateTime Timestamp { get; set; }}// 必须为 AOT 创建 JsonSerializerContext[JsonSerializable(typeof(GreetingResponse))][JsonSerializable(typeof(string))]internal partial class AppJsonSerializerContext : JsonSerializerContext{}创建Startup.cs注意AOT 类库中没有Startup类我们直接构建 WebApplicationcsharpusing Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.DependencyInjection;public class ApiStartup{ // 返回一个配置好的 WebApplication 实例 public static WebApplication CreateApp(string[] args) { var builder WebApplication.CreateSlimBuilder(args); // 明确注册 JSON 序列化上下文避免反射 builder.Services.ConfigureHttpJsonOptions(options { options.SerializerOptions.TypeInfoResolver AppJsonSerializerContext.Default; }); var app builder.Build(); // 定义 GET /greet 端点 app.MapGet(/greet, (string? name) { var response new GreetingResponse { Message $Hello, {name ?? World}!, Timestamp DateTime.UtcNow }; return Results.Json(response, AppJsonSerializerContext.Default.GreetingResponse); }); return app; }}### 4. 配置 AOT 编译编辑AotApiLibrary.csproj添加以下属性xmlPropertyGroup PublishAottrue/PublishAot OptimizationPreferenceSpeed/OptimizationPreference/PropertyGroup然后发布为 AOT 类库注意类库发布 AOT 后会生成.aot文件但我们需要的是 DLL 引用所以这一步只是为了验证编译成功bashdotnet publish -c Release -r win-x64## 第二步创建 WPF 项目并引用 AOT 类库### 1. 新建 WPF 项目bashdotnet new wpf -n WpfAppWithAot -f net8.0### 2. 添加项目引用bashcd WpfAppWithAotdotnet add reference ../AotApiLibrary/AotApiLibrary.csproj### 3. 修改 WPF 的MainWindow.xaml.cs我们将在 WPF 窗口初始化时启动内嵌的 ASP.NET Core 服务器并绑定到一个本地端口。MainWindow.xaml简化版xmlWindow x:ClassWpfAppWithAot.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml TitleWPF ASP.NET Core AOT Height200 Width400 StackPanel VerticalAlignmentCenter HorizontalAlignmentCenter TextBlock Text内嵌 Web 服务器已启动 FontSize16 / Button Content测试 API ClickOnTestApi Margin0,10 / TextBlock x:NameResultText Text等待测试... / /StackPanel/WindowMainWindow.xaml.cs核心代码csharpusing System;using System.Net.Http;using System.Threading.Tasks;using System.Windows;using Microsoft.AspNetCore.Hosting;namespace WpfAppWithAot{ public partial class MainWindow : Window { private IDisposable _webHost; // 用于管理 Web 服务器的生命周期 public MainWindow() { InitializeComponent(); StartWebServer(); } /// summary /// 启动内嵌的 ASP.NET Core AOT Web 服务器 /// /summary private void StartWebServer() { // 注意这里使用 AotApiLibrary 中的 ApiStartup 类 var app AotApiLibrary.ApiStartup.CreateApp(new string[] { --urls, http://localhost:5000 }); _webHost app.RunAsync(); // 异步启动不会阻塞 UI 线程 } /// summary /// 测试按钮点击事件调用本地的 API /// /summary private async void OnTestApi(object sender, RoutedEventArgs e) { try { using var httpClient new HttpClient(); var response await httpClient.GetStringAsync(http://localhost:5000/greet?nameWPF); ResultText.Text $API 返回: {response}; } catch (Exception ex) { ResultText.Text $错误: {ex.Message}; } } /// summary /// 窗口关闭时停止 Web 服务器 /// /summary protected override void OnClosed(EventArgs e) { _webHost?.Dispose(); base.OnClosed(e); } }}### 4. 运行与测试按 F5 运行 WPF 应用你会看到窗口显示“内嵌 Web 服务器已启动”。点击“测试 API”按钮结果将显示从本地 API 返回的 JSON 数据。## 代码示例详解### 示例 1AOT 类库中的 JSON 序列化上下文这段代码的关键在于[JsonSerializable]特性。AOT 编译无法使用System.Text.Json默认的反射式序列化所以我们需要显式声明哪些类型会被序列化。AppJsonSerializerContext继承自JsonSerializerContext它会在编译时生成具体的序列化代码而不是运行时反射。csharp[JsonSerializable(typeof(GreetingResponse))][JsonSerializable(typeof(string))]internal partial class AppJsonSerializerContext : JsonSerializerContext{}注意partial关键字必不可少因为编译器会自动生成AppJsonSerializerContext的实现部分。### 示例 2WPF 中启动内嵌 Web 服务器这里我们调用了AotApiLibrary.ApiStartup.CreateApp它返回一个WebApplication对象。RunAsync()方法会启动服务器并监听端口但由于它是异步的我们需要将其分配给一个IDisposable字段以便在窗口关闭时释放资源。csharpvar app AotApiLibrary.ApiStartup.CreateApp(new string[] { --urls, http://localhost:5000 });_webHost app.RunAsync();潜在问题如果 WPF 的 UI 线程阻塞RunAsync可能不会立即启动。解决方案是确保CreateApp和RunAsync在非 UI 线程上执行但这里RunAsync本身就是异步的不会阻塞。## 进阶优化与调试### 性能对比你可以在 WPF 的OnTestApi中添加计时对比 AOT 版本与普通 JIT 版本的启动时间。通常 AOT 版本的 API 响应时间更稳定首次调用延迟更低。### 端口冲突如果 5000 端口被占用可以动态分配端口csharpvar port new Random().Next(10000, 60000);var app ApiStartup.CreateApp(new[] { $--urlshttp://localhost:{port} });### 发布为单文件WPF 项目也可以结合 AOT 类库发布为单文件应用bashdotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFiletrue## 总结通过本文我们成功实现了1.创建 ASP.NET Core AOT 类库通过[JsonSerializable]和最小 API 模式让代码兼容 AOT 编译。2.在 WPF 中内嵌 Web 服务器利用WebApplication.RunAsync()在桌面应用生命周期内运行 HTTP 服务。3.实现端到端调用WPF 界面通过 HttpClient 调用本地 API获取 JSON 响应。这种架构特别适合需要提供本地 API 的桌面工具、自动化测试框架或轻量级微服务边缘场景。AOT 编译带来的性能提升启动时间减少 50% 以上内存降低 30%让桌面应用也能拥有 Web 服务的灵活性。最后提醒AOT 编译并非万能——它限制了动态代码生成如 EFCore 的 LINQ 查询但如果你坚持使用静态类型和显式序列化AOT 绝对是桌面应用现代化的利器。现在不妨在你的下一个 WPF 项目中尝试一下
RELATED

相关推荐

PTH-RP肽段序列分析及生物活性应用指南

PTH-RP肽段序列分析及生物活性应用指南

1. 肽段序列PTH-RP (140-173) (human)的生物学背景解析 PTH-RP(甲状旁腺激素相关蛋白)是一种在多种组织中表达的多功能蛋白质,其140-173片段在人体生理和病理过程中扮演着重要角色。这个由34个氨基酸组成的肽段序列"TALLWGLKKKKENNRRTHH…

📅 2026/8/23 2:02:38
Unity 2022.3 Android打包报错:Could not resolve all files for configuration 深度解析与解决方案

Unity 2022.3 Android打包报错:Could not resolve all files for configuration 深度解析与解决方案

1. 项目概述:一个困扰无数开发者的“文件解析”拦路虎 “Could not resolve all files for configuration:” 这个报错,对于任何一个使用 Unity 2022.3 或相近版本进行 Android 平台打包的开发者来说,都像是一个不期而遇的“老朋友”。它总是…

📅 2026/9/12 13:28:39
3分钟掌握Video Download Helper:网页视频离线保存的终极解决方案

3分钟掌握Video Download Helper:网页视频离线保存的终极解决方案

3分钟掌握Video Download Helper:网页视频离线保存的终极解决方案 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 在数字内容爆炸…

📅 2026/8/23 2:02:39
MORE NEWS

更多资讯

📰

RoPE复数形式全解:旋转位置编码的几何意义与注意力分数推导

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

代码转流程图:开发者的逻辑可视化刚需工具指南

1. 为什么“代码转流程图”不是锦上添花,而是开发日常的刚需?你有没有过这样的经历:接手一个没人维护的老项目,打开源码——满屏嵌套三层以上的 if-else、十几层缩进的 for 循环、函数调用链像迷宫一样绕来绕去?光看代…

📰

机械臂仿真链路:从URDF到Simscape再到S-Function的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Git SSH密钥配置、ed25519与多账号排查指南

周六下午,同事在群里甩过来一句"git push 一直报 Permission denied (publickey)",配了张终端截图。我扫了一眼就知道,又是 SSH 密钥没配明白。这类问题从我第一次自己搭 Git 仓库到现在,前前后后大概处理过几百次,踩过的坑能写满一整页笔记。git 中的 SSH 密钥的配置…

📰

Dev-C++ 5.11 安装配置与使用指南:从下载到调试的完整教程

大学生涯里,你大概率会在一门叫“C语言程序设计”的课上第一次认识Dev-C。这个蓝白色调、界面看起来跟时代脱节的IDE,最新稳定版本Orwell Dev-C 5.11发布已经快十年了,可你去任何一所高校的计算机机房看,桌面上十有八九还躺着这个…

📰

IEPE传感器全解析:从压电效应到工程实践的振动测量指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬