在 WPF 中集成 ASP.NET Core 和 WebView2 用于集成 SPA 应用
背景
我们有些工具在 Web 版中已经有了很好的实践,而在 WPF 中重新开发也是一种费时费力的操作,那么直接集成则是最省事省力的方法了。
修改项目文件
我们首先修改项目文件,让 WPF 项目可以包含 ASP.NET Core 的库,以及引用 WebView2 控件。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<!-- 这里插入 WebView2 的包,用于显示网页 -->
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2478.35" />
<!-- 这里插入 ASP.NET Core 的框架引用,用于代理资源文件 -->
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<!-- 这里模仿 ASP.NET Core,将 SPA 资源文件存于 wwwroot 文件夹下 -->
<None Update="wwwroot\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
修改 App.xaml 和 App.xaml.cs 以使用 ASP.NET Core 的 WebApplication.CreateBuilder()
这里为了全局使用依赖注入,我们将 WebApplication.CreateBuilder() 放在 App.xaml.cs 中全局使用。为了使用依赖注入应注释掉默认启动窗口,并接管 Startup 事件。
<Application x:Class="WpfAircraftViewer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAircraftViewer"
Startup="ApplicationStartup">
<!-- 这里将 StartupUri 属性删除,然后注册 Startup 事件 -->
<Application.Resources>
</Application.Resources>
</Application>
然后通过修改 Startup 事件的代码来实现相应的加载动作。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using System.Windows;
namespace WpfAircraftViewer
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, IAsyncDisposable
{
public WebApplication? WebApplication { get; private set; }
public async ValueTask DisposeAsync()
{
if (WebApplication is not null)
{
await WebApplication.DisposeAsync();
}
GC.SuppressFinalize(this);
}
private async void ApplicationStartup(object sender, StartupEventArgs e)
{
// 这里是创建 ASP.NET 版通用主机的代码
var builder = WebApplication.CreateBuilder(Environment.GetCommandLineArgs());
// 注册主窗口和其他服务
builder.Services.AddSingleton<MainWindow>();
builder.Services.AddSingleton(this);
var app = builder.Build();
// 这里是文件类型映射,如果你的静态文件在浏览器中加载报 404,那么需要在这里注册,这里我加载一个 3D 场景文件的类型
var contentTypeProvider = new FileExtensionContentTypeProvider();
contentTypeProvider.Mappings[".glb"] = "model/gltf-binary";
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = contentTypeProvider,
});
// 你如果使用了 Vue Router 或者其他前端路由了,需要在这里添加这句话让路由返回前端,而不是 ASP.NET Core 处理
app.MapFallbackToFile("/index.html");
WebApplication = app;
// 处理退出事件,退出 App 时关闭 ASP.NET Core
Exit += async (s, e) => await WebApplication.StopAsync();
// 显示主窗口
MainWindow = app.Services.GetRequiredService<MainWindow>();
MainWindow.Show();
await app.RunAsync().ConfigureAwait(false);
}
}
}
此时,我们已经可以正常开启一个默认界面的 MainWindow 了。
使用 WebView2 控件
这时我们就可以先将 SPA 文件从 npm 项目的 dist 复制到 wwwroot 了,在编辑 MainWindow 加入 WebView2 控件后就可以查看了。
<Window x:Class="WpfAircraftViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:local="clr-namespace:WpfAircraftViewer"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
mc:Ignorable="d" MinHeight="450" MinWidth="800" SnapsToDevicePixels="True">
<!-- 在上面加入 xmlns:wv2 属性用于引用 WebView2 控件 -->
<Grid>
<!-- 这里插入 WebView2 控件,我们默认可以让 Source 是 http://localhost:5000,这是 ASP.NET Core 的默认监听地址 -->
<wv2:WebView2 Name="webView"
Source="{Binding SourceUrl, FallbackValue='http://localhost:5000'}" AllowDrop="True" SnapsToDevicePixels="True"/>
</Grid>
</Window>
我们可以继续编辑窗口的信息,让他可以关联 ASP.NET Core 的监听地址。
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using System.Windows;
namespace WpfAircraftViewer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public string SourceUrl { get; set; }
public MainWindow(IServer server)
{
InitializeComponent();
// 这里通过注入的 IServer 对象来获取监听的 Url
var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses;
SourceUrl = addresses is not null ? (addresses.FirstOrDefault() ?? "http://localhost:5000") : "http://localhost:5000";
// 无 VM,用自身当 VM
DataContext = this;
}
}
}
这时我们就可以看到窗口打开了我们的 SPA 页面了。

在 WPF 中集成 ASP.NET Core 和 WebView2 用于集成 SPA 应用的更多相关文章
- 【译】.NET 7 预览版 1 中的 ASP.NET Core 更新
原文 | Daniel Roth 翻译 | 郑子铭 .NET 7 预览版 1 现已推出!这是 .NET 下一个主要版本的第一个预览版,其中将包括使用 ASP.NET Core 进行 Web 开发的下一 ...
- 在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序
前言 Visual Studio 2017已经发布了很久了.做为集成了Asp.Net Core 1.1的地表最强IDE工具,越来越受.NET系的开发人员追捧. 随着Google Angular4的发布 ...
- 【Asp.Net Core】在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序
前言 Visual Studio 2017已经发布了很久了.做为集成了Asp.Net Core 1.1的地表最强IDE工具,越来越受.NET系的开发人员追捧. 随着Google Angular4的发布 ...
- 5. abp集成asp.net core
一.前言 参照前篇<4. abp中的asp.net core模块剖析>,首先放张图,这也是asp.net core框架上MVC模块的扩展点 二.abp的mvc对象 AbpAspNetCor ...
- 从零搭建一个IdentityServer——集成Asp.net core Identity
前面的文章使用Asp.net core 5.0以及IdentityServer4搭建了一个基础的验证服务器,并实现了基于客户端证书的Oauth2.0授权流程,以及通过access token访问被保护 ...
- 在docker中运行ASP.NET Core Web API应用程序
本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Cor ...
- 在Linux和Windows的Docker容器中运行ASP.NET Core
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott H ...
- 丙申年把真假美猴王囚禁在容器中跑 ASP.NET Core 1.0
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- Docker容器中运行ASP.NET Core
在Linux和Windows的Docker容器中运行ASP.NET Core 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了. ...
- docker中运行ASP.NET Core Web API
在docker中运行ASP.NET Core Web API应用程序 本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过 ...
随机推荐
- #拓扑排序#洛谷 5157 [USACO18DEC]The Cow Gathering P
题目 给出一棵树和一些限制关系 \((a_i,b_i)\), 一种合法的删点序列当且仅当删除一个点之后树的大小不超过 1 或不存在孤立点, 并且 \(a_i\) 要比 \(b_i\) 先删除,问 \( ...
- 单元测试篇2-TDD三大法则解密
引言 在我们上一篇文章了解了单元测试的基本概念和用法之后,今天我们来聊一下 TDD(测试驱动开发) 测试驱动开发 (TDD) 测试驱动开发英文全称是Test Driven Development 简称 ...
- 【直播回顾】OpenHarmony知识赋能五期第三课——多媒体整体介绍
5月5日晚上19点,知识赋能第五期第三节课<OpenHarmony标准系统多媒体子系统整体介绍>,在OpenHarmony开发者成长计划社群内成功举行. 本期课程,由深开鸿资深技术专家郭岳 ...
- 本周四晚19:00知识赋能第3期直播丨OpenHarmony智能家居项目之控制面板功能实现
OpenAtom OpenHarmony(以下简称"OpenHarmony")开源开发者成长计划项目自 2021 年 10 月 24 日上线以来,在开发者中引发高度关注. 成长计划 ...
- [一本通1677/JZOJ1217/CJOJ1101]软件开发 题解
题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成\(m\)个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用 ...
- 拥抱开源更省钱「GitHub 热点速览」
免费.低成本.自托管.开源替代品...这些词就是本周的热门开源项目的关键字.常见的 AI 提升图片分辨率的工具,大多是在线服务或者调用接口的客户端,而「Upscaler」是一款下载即用的免费 AI 图 ...
- 20个Python 正则表达式应用与技巧
本文分享自华为云社区<Python 正则表达式大揭秘应用与技巧全解析>,作者:柠檬味拥抱. Python 中的 re 模块是用于处理正则表达式的强大工具.正则表达式是一种用来匹配字符串的模 ...
- 树模型-CART树
分类回归树CART CART树是后面所有模型的基础,也是核心树 在ID3算法中我们使用了信息增益来选择特征,信息增益大的优先选择.在C4.5算法中,采用了信息增益比来选择特征,以减少信息增益容易选择特 ...
- CentOS 7.9编译安装Python-3.10.13
目录 查看CentOS版本.系统默认gcc版本.Python版本和pip版本 部署Python-3.10.13 测试 将yum中的Python版本修改为系统原来的2.7.5版本 查看CentOS版本. ...
- Pytorch风格迁移代码
最近研究了一下风格迁移,主要是想应用于某些主题节日时动态融合背景,生成一些抽象的艺术图片,这里给大家分享一个现成的代码,我本地把环境搭建好后跑了试试,有兴趣的可以直接拿去运行: 1 import to ...