在 WPF 中集成 ASP.NET Core 和 WebView2 用於集成 SPA 應用

来源:https://www.cnblogs.com/aobaxu/p/18186785
-Advertisement-
Play Games

背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...


背景

我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。

思路解釋

  1. 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron 小很多,release 後的體積主要是 ASP.NET Core 的文件。
  2. 為什麼要使用 ASP.NET Core 進行代理呢?很簡單,因為很多操作要求使用 HTTP Context,在類似 file:/// 的鏈接下是不能使用的,如果做成聯網的有些資源進行跨域請求也是不能的。舉個很簡單的例子,vite 打包後的 SPA 如果直接點開那麼裡面打包的 ES Module 的文件全部不允許請求。
  3. 那你這個項目不聯網能用嗎?看你的需求了,不聯網當然能用,這裡集成的 SPA 不一定全部都得是完整的 SPA,整套集成如果客戶在有網的環境下可以直接引用網頁的 URL 就好了。比如我們要用 monaco-editor 或者其他的文字編輯器又或者是 3D 編輯器,在 C# 上找不到或不好找到類似的庫,那麼集成 npm 上現成的庫就是最佳選擇。

修改項目文件

我們首先修改項目文件,讓 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.xamlApp.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 頁面了。

示例代碼


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在現代社會中,機動車已經成為人們生活的重要交通工具。而行駛證作為機動車的身份證明,具有重要的法律效力。然而,對於行駛證上的信息進行手工識別是一項繁瑣的工作,容易出現錯誤,並且耗時較長。為瞭解決這個問題,挖數據平臺提供了行駛證OCR識別Api介面,可以對行駛證上的信息進行快速準確地識別和提取。 這個A ...
  • 大家好,我是 Java陳序員。 問君能有幾多愁,開源項目解千愁! 今天,給大家介紹一個快速開發平臺,完全開源可商用! 關註微信公眾號:【Java陳序員】,獲取開源項目分享、AI副業分享、超200本經典電腦電子書籍等。 項目介紹 SmartAdmin —— 一個簡潔、高效、安全的快速開發平臺,以高質 ...
  • 大家好,我是R哥。 金三銀四結束了,上個月分享了一個 35K 入職的面試輔導案例: 35K*14 薪入職了,這公司只要不裁員,我能一直呆下去。。 今天再分享一個上個月讓人很有成就感的面試輔導 case: 外包、空窗四個月、薪資 10k、996 ——> 甲方公司、薪資15k、早九晚六(WLB),從報名 ...
  • 當一個線程被啟動後,如果再次調start()方法,將會拋出IllegalThreadStateException異常。 這是因為Java線程的生命周期只有一次。調用start()方法會導致系統在新線程中運行執行體,但是如果線程已經結束,則不能再次使用,需要重新創建一個新的線程對象並調用start()... ...
  • 正文 昨天玩到了凌晨 3 點,今天睡了一天…… 斷斷續續睡到 12 點起床,下午又從 5 點睡到了 7 點。我願稱之為睡神……. 其它時間就是做工作日一直沒時間做的雜事,比如洗衣服,刷鞋,換洗被套什麼的,還挺花時間。用了得有兩三個小時。 所以昨天說的今天開擺,那是真的開擺了 (笑。 現在晃一下頭,能 ...
  • 1. Spring6 的JdbcTemplate的JDBC模板類的詳細使用說明 @目錄1. Spring6 的JdbcTemplate的JDBC模板類的詳細使用說明每博一文案2. 環境準備3. 數據準備4. 開始4.1 從數據表中插入(添加)數據4.2 從數據表中修改數據4.3 從數據表中刪除數據4 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...