首页
/ 在 ASP.NET Core 中通过 ZIP 包集成 CKEditor 5:完整实战指南

在 ASP.NET Core 中通过 ZIP 包集成 CKEditor 5:完整实战指南

2026-09-15 22:35:49作者:卓艾滢Kingsley

CKEditor 5 本质上是一个纯 JavaScript/TypeScript 的富文本编辑器库,没有任何官方 .NET 专属集成,因此它可以被部署到任何能托管静态资源的服务端环境——包括 Microsoft 的 .NET 平台。本文基于 .NET 集成文档 的完整流程,演示如何在 ASP.NET Core 应用中通过 ZIP 归档放置自定义编辑器构建,并通过 import map 与 ES Module 语法完成页面集成,最终用 dotnet watch run 启动应用。读完本文,你将掌握从项目搭建、静态资源托管、Razor 页面改造到 license key 配置的端到端实操能力。

集成方式总览:为什么选择 ZIP 自托管

把 CKEditor 5 放进 .NET 应用,主要有两种分发路径:

维度 CDN(云托管) ZIP 归档(自托管)
资源来源 cdn.ckeditor.com 全局分发 从 Customer Portal 下载并解压到 wwwroot
托管成本 无需自建静态资源服务 需要自己托管静态文件
许可证 需商业许可,不支持 'GPL' 支持 GPL 或自托管商业许可
适合场景 快速接入、云端计费 内网/私有化部署、离线环境、灵活控制版本

采用 ZIP 自托管时,你从 Customer Portal 下载包含自定义构建的 ZIP 包(通常是使用 CKEditor 5 Builder 生成的、包含所选插件与工具栏的构建产物),将其中两个产物——ckeditor5.jsckeditor5.css——复制到项目的 wwwroot/lib/ckeditor5/ 目录。由于没有官方 .NET 集成,应用只需负责把这些静态资源原样提供给浏览器,编辑器在浏览器端以 ES Module 方式加载并实例化。

自托管下使用商业构建,需要为自托管分发获得相应许可;GPL 合规场景可直接使用开源许可。具体授权约束见下文「license key 配置」小节。

创建 ASP.NET Core 项目

本文以 dotnet new webapp 创建的 ASP.NET Core Web 应用(Razor Pages 模板)为例:

dotnet new webapp

该命令会生成包含 Pages/wwwroot/appsettings.json 等目录的骨架项目。若需从零了解 ASP.NET Core 框架本身,可参考微软官方 ASP.NET Core 入门文档;本文后续步骤只需一个能正常返回页面并托管静态文件的项目即可。

下载 ZIP 包并复制静态资源

获取构建产物

CKEditor 5 Builder 中配置好所需插件与工具栏后下载 ZIP 归档。解压后,把其中两个文件复制到静态资源目录:

# 假设解压目录为 ./ckeditor5-dist
mkdir -p wwwroot/lib/ckeditor5
cp ./ckeditor5-dist/ckeditor5.js  wwwroot/lib/ckeditor5/
cp ./ckeditor5-dist/ckeditor5.css wwwroot/lib/ckeditor5/

预期的目录结构

完成后,应用的文件夹结构应与下面类似:

├── bin
├── obj
├── Pages
│   ├── Index.cshtml
│   └── ...
├── Properties
├── wwwroot
│   ├── css
│   ├── js
│   ├── lib
│   │   ├── bootstrap
│   │   ├── ckeditor5
│   │   │   ├── ckeditor5.js
│   │   │   └── ckeditor5.css
│   │   ├── jquery
│   │   ├── jquery-validation
│   │   └── jquery-validation-unobtrusive
│   └── favicon.ico
├── appsettings.Development.json
├── appsettings.json
└── ...

关键点:ckeditor5.jsckeditor5.css 必须处于同一目录(本例为 wwwroot/lib/ckeditor5/),因为 JS 文件内部会按相对路径解析其依赖的 CSS、图标等资源。

自托管版本的 license key 要求

从版本 44.0.0 起,licenseKey 配置项成为使用编辑器的必要条件。使用 ZIP 自托管版本时,必须满足以下二选一:

  • 遵守 GPL:将 licenseKey 配置为 'GPL'
  • 获取自托管分发的商业许可:配置你在 Customer Portal 中获得的商业 license key。

如果只是想评估自托管方案,可以在 CKEditor 5 Customer Portal 申请免费试用来测试编辑器并评估自托管分发。

改造 Razor 页面:Index.cshtml 完整模板

ZIP 包内的 index.html 已包含全部必要标记(import map、CSS 链接与模块化初始化脚本)。将其移植到 Pages/Index.cshtml<script> 标签中即可,但务必注意 import map 与 CSS 链接的路径要与你的实际目录结构一致。以下是一份可直接套用的完整模板:

@page
@using Microsoft.AspNetCore.Components
@{
    ViewData["Title"] = "Home Page";
    var data = new ImportMapDefinition(
    new Dictionary<string, string>
    {
        { "ckeditor5", "/lib/ckeditor5/ckeditor5.js" },
        { "ckeditor5/", "/lib/ckeditor5/" },
    }, null, null);
}
<link href="~/lib/ckeditor5/ckeditor5.css" rel="stylesheet" />
<div class="main-container">
    <div id="editor">
        <p>Hello from CKEditor 5!</p>
    </div>
</div>
<script type="importmap" asp-importmap="@data"></script>
<script type="module">
    import {
        ClassicEditor,
        Essentials,
        Paragraph,
        Bold,
        Italic,
        Font
    } from 'ckeditor5';

    ClassicEditor
        .create( {
            attachTo: document.querySelector( '#editor' ),
            licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
            plugins: [ Essentials, Paragraph, Bold, Italic, Font ],
            toolbar: [
                'undo', 'redo', '|', 'bold', 'italic', '|',
                'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor'
            ]
        } )
        .then( editor => {
            window.editor = editor;
        } )
        .catch( error => {
            console.error( error );
        } );
</script>

模板要点逐项解析

  1. @using Microsoft.AspNetCore.ComponentsImportMapDefinition:Razor 页面通过 ImportMapDefinition 在服务端构建浏览器原生 import map,把裸模块名 ckeditor5 映射到 /lib/ckeditor5/ckeditor5.js,并把 ckeditor5/ 前缀映射到 /lib/ckeditor5/ 目录(用于解析内部相对依赖)。asp-importmap 标签助手负责将该对象序列化为 <script type="importmap">
  2. CSS 链接<link href="~/lib/ckeditor5/ckeditor5.css" rel="stylesheet" /> 中的 ~ 是 Razor 静态资源根路径语法,对应 wwwroot 目录。
  3. 编辑器容器<div id="editor"> 是编辑器的挂载点,其内部预置的 <p>Hello from CKEditor 5!</p> 会成为编辑器的初始内容。
  4. ES Module 导入<script type="module"> 中从 ckeditor5(由 import map 解析)按命名方式导入 ClassicEditor 与各插件类。
  5. .create() 配置
    • attachTo:指定编辑器挂载的 DOM 元素(#editor);
    • licenseKey:必填,商业 key 或 'GPL'
    • plugins:声明实际加载的插件,此处包含 EssentialsParagraphBoldItalicFont
    • toolbar:工具栏按钮顺序,'|' 表示分隔符,fontSize/fontFamily/fontColor/fontBackgroundColor 均由 Font 插件提供。
  6. 异步生命周期create() 返回 Promise,.then( editor => { window.editor = editor; } ) 把实例挂到全局便于调试;.catch() 负责打印初始化错误。

注意:ZIP 构建里包含哪些插件,取决于你在 Builder 中选择的预设。上例中的插件与工具栏按钮仅对应文档示例,实际使用时应与你的构建产物保持一致,否则导入不存在的模块会报错。

处理 Chromium 的 import map 限制

由于 Chromium 内核的已知问题(chromium issue 40611854),浏览器目前不支持同时存在多个 import map。当前版本的 .NET Web 应用模板可能已经在共享布局中定义了一个 import map。如果你遇到这种情况:

  1. 打开 /Pages/Shared/__Layout.cshtml
  2. 删除其中已有的 <script type="importmap"></script> 标签(或对应内容);
  3. 刷新页面,编辑器即可正常加载。

删除共享布局中的 import map 不会影响应用其他功能,因为该 import map 在本集成中由 Index.cshtml 内的新 import map 完全接管。

启动应用

在 .NET 项目根目录执行:

dotnet watch run

dotnet watch run 会构建项目、启动 Kestrel,并监听源文件变化自动重启/刷新。浏览器访问应用主页后,即可在 #editor 容器中看到 CKEditor 5 编辑器实例。

licenseKey 配置的底层校验逻辑

了解编辑器端如何校验 licenseKey,有助于排查自托管集成中的授权问题。从 editor.ts 的源码可以看到,编辑器初始化时依次执行:

  1. 读取配置config.get( 'licenseKey' )
  2. 全局键兜底:若配置缺失,会检查 window.CKEDITOR_GLOBAL_LICENSE_KEY 全局变量,存在则自动写入配置;
  3. 缺失即报错:若最终仍无 license key,抛出 license-key-missingCKEditorError,错误信息中明确提示:商业场景请提供 key,GPL 场景请使用 'GPL'

editorconfig.ts 中,licenseKey 被声明为 EditorConfig 的可选字符串属性。校验通过后,编辑器还会根据 key 类型(GPL / 商业 JWT 载荷)决定是否启用只读限制、显示 "Powered by CKEditor" 标识等行为(见 editor.tsverifyLicenseKey 的实现)。

这一点对 ZIP 自托管尤其重要:如果页面里忘记写 licenseKey,即使资源路径全部正确,编辑器也会在初始化阶段直接抛错,而不会静默降级。

常见问题与排错清单

症状 排查方向
浏览器控制台报 license-key-missing 确认 create() 配置中已写 licenseKey: '<YOUR_LICENSE_KEY>''GPL'(44.0.0 起强制要求)
编辑器不渲染,模块导入 404 核对 wwwroot/lib/ckeditor5/ckeditor5.jsckeditor5.css 是否存在,以及 import map 中 /lib/ckeditor5/... 路径是否与目录结构一致
出现多个 import map 相关报错 删除 Pages/Shared/__Layout.cshtml 中已有的 <script type="importmap"> 标签
工具栏按钮与导入的插件不匹配 确认 pluginstoolbar 项来自你在 Builder 中选定的构建预设
修改后页面不刷新 确认是用 dotnet watch run 启动,且改动的是受监听的文件

后续深入方向

  • 学习如何读取、修改编辑器数据并监听变化:获取与设置数据
  • 进一步定制编辑器行为与配置项:配置指南
  • 了解工具栏按钮的完整定制方式:工具栏配置
  • 查看各功能模块的独立指南:功能总览
  • 若你更希望走 CDN 云分发路线(无需自托管静态资源),可参考同系列的 .NET CDN 集成,两种方式的页面骨架几乎一致,只是资源来源与许可要求不同。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
953
1.87 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
538
615
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.37 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.29 K
1.04 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.4 K
1.49 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
403
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
348