From 1bf508a717094b2ecfaa7a0fc9d3555f01660069 Mon Sep 17 00:00:00 2001 From: jx Date: Sun, 17 Aug 2025 15:46:14 +0800 Subject: [PATCH 1/9] =?UTF-8?q?Editor=E5=A2=9E=E5=8A=A0Upload=E5=9B=9E?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/Editor.razor.cs | 39 +++++- .../Components/Editor/Editor.razor.js | 27 +++- .../Components/Editor/EditorUploadFile.cs | 115 ++++++++++++++++++ 3 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs index 4660d0d0..ad30bde1 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs @@ -60,6 +60,12 @@ public partial class Editor [Parameter] public bool ShowSubmit { get; set; } = true; + /// + /// 获得/设置 Editor组件内上传文件时回调此方法 + /// + [Parameter] + public Func>? OnFileUpload { get; set; } + private bool _lastShowSubmit = true; private string? ShowSubmitString => ShowSubmit ? "true" : null; @@ -83,7 +89,7 @@ public partial class Editor public string? Language { get; set; } /// - /// 获得/设置 语言扩展脚本路径 默认 null 如加载德语可设置为 + /// 获得/设置 语言扩展脚本路径 默认 null 如加载德语可设置为 /// [Parameter] public string? LanguageUrl { get; set; } @@ -186,7 +192,7 @@ protected override async Task InvokeInitAsync() methodClickPluginItem = nameof(ClickPluginItem); } - await InvokeVoidAsync("init", Id, Interop, methodGetPluginAttributes, methodClickPluginItem, Height, Value ?? "", Language, LanguageUrl); + await InvokeVoidAsync("init", Id, Interop, methodGetPluginAttributes, methodClickPluginItem, Height, Value ?? "", Language, LanguageUrl, OnFileUpload is not null); } /// @@ -256,6 +262,35 @@ public async Task ClickPluginItem(string pluginItemName) return ret; } + /// + /// 文件上传回调 + /// + /// + [JSInvokable] + public async Task ImageUpload(EditorUploadFile uploadFile) + { +#if NET6_0_OR_GREATER + var ret = ""; + if (Module != null) + { + var stream = await InvokeAsync("fetch", Id, uploadFile.Index); + if (stream != null) + { + using var data = await stream.OpenReadStreamAsync(); + uploadFile.UploadStream = data; + if (OnFileUpload != null) + { + ret = await OnFileUpload(uploadFile); + } + } + } + return ret; +#else + await Task.Yield(); + throw new NotSupportedException(); +#endif + } + /// /// 执行 editor 的方法 /// diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js index a0b6bb8f..f16d9c47 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js @@ -7,7 +7,7 @@ if (window.BootstrapBlazor === void 0) { window.BootstrapBlazor = {}; } -export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginItem, height, value, lang, langUrl) { +export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginItem, height, value, lang, langUrl, hasUpload) { const el = document.getElementById(id) if (el === null) { return @@ -46,6 +46,26 @@ export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginI const showSubmit = el.getAttribute("data-bb-submit") === "true" option.toolbar = toolbar; reloadCallbacks(id, option); + if (hasUpload) { + option.callbacks.onImageUpload = function (files) { + editor.files = files + for (let i = 0; i < files.length; i++) { + const file = files[i]; + editor.invoker.invokeMethodAsync('ImageUpload', { + fileName: file.name, + fileSize: file.size, + contentType: file.type, + lastModified: new Date(file.lastModified).toISOString(), + index: i + }).then(data => { + if (data !== "") { + editor.$editor.summernote('insertImage', data, file.name) + } + }) + } + } + } + if (!showSubmit) { const externalOnChange = option.callbacks.onChange; option.callbacks.onChange = function (contents) { @@ -146,6 +166,11 @@ export function update(id, val) { } } +export function fetch(id, index) { + const md = Data.get(id) + return md.files[index] +} + export function invoke(id, method, parameter) { const editor = Data.get(id) editor.$editor.summernote(method, ...parameter) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs b/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs new file mode 100644 index 00000000..3e203351 --- /dev/null +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs @@ -0,0 +1,115 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 文件信息 +/// +public class EditorUploadFile +{ + /// + /// 文件名 + /// + public string? FileName { get; set; } + + /// + /// 文件大小 + /// + public long FileSize { get; set; } + + /// + /// 最后修改日期 + /// + public string? LastModified { get; set; } + + /// + /// 文件类型 + /// + public string? ContentType { get; set; } + + /// + /// 上传的文件流 + /// + public Stream? UploadStream { get; set; } + + /// + /// 文件索引 + /// 用于标识文件在上传列表中的位置 + /// 例如在上传多个文件时可以通过此属性区分每个文件的索引位置 + /// + public int Index { get; set; } + + /// + /// 返回码,0为成功,非0失败 + /// + public int Code { get; set; } + + /// + /// 错误信息 + /// + public string? Error { get; set; } + + /// + /// 保存到文件 + /// + /// + /// + /// + public async Task SaveToFile(string fileName, CancellationToken token = default) + { + var ret = false; + if (UploadStream != null) + { + // 文件保护,如果文件存在则先删除 + if (System.IO.File.Exists(fileName)) + { + try + { + System.IO.File.Delete(fileName); + } + catch (Exception ex) + { + Code = 1002; + Error = ex.Message; + } + } + + var folder = Path.GetDirectoryName(fileName); + if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + if (Code == 0) + { + using var uploadFile = File.OpenWrite(fileName); + + try + { + // 打开文件流 + var stream = UploadStream; + + var buffer = new byte[4 * 1096]; + int bytesRead = 0; + + // 开始读取文件 + while ((bytesRead = await stream.ReadAsync(buffer, token)) > 0) + { + await uploadFile.WriteAsync(buffer.AsMemory(0, bytesRead), token); + + } + ret = true; + } + catch (Exception ex) + { + Code = 1003; + Error = ex.Message; + } + } + } + return ret; + } + +} From f15eafdcd80f2aa2d4219584e3e1fc3979c16359 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 17 Aug 2025 18:32:55 +0800 Subject: [PATCH 2/9] chore: bump version 9.0.2 --- .../BootstrapBlazor.CodeEditor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/BootstrapBlazor.CodeEditor/BootstrapBlazor.CodeEditor.csproj b/src/components/BootstrapBlazor.CodeEditor/BootstrapBlazor.CodeEditor.csproj index 417c937d..ecb39621 100644 --- a/src/components/BootstrapBlazor.CodeEditor/BootstrapBlazor.CodeEditor.csproj +++ b/src/components/BootstrapBlazor.CodeEditor/BootstrapBlazor.CodeEditor.csproj @@ -1,7 +1,7 @@ - 9.0.1 + 9.0.2 From 1101bb2a20acb65da626945f1b6c449461399915 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 13:04:41 +0800 Subject: [PATCH 3/9] =?UTF-8?q?doc:=20=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/Editor.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs index ad30bde1..b9c5be77 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs @@ -61,7 +61,7 @@ public partial class Editor public bool ShowSubmit { get; set; } = true; /// - /// 获得/设置 Editor组件内上传文件时回调此方法 + /// 获得/设置 Editor 组件内上传文件时回调此方法 /// [Parameter] public Func>? OnFileUpload { get; set; } From c43af81d6a960fa6def83c7a8fa48aa7acef6623 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 13:05:04 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=9B=BE=E7=89=87=E8=8A=82=E7=82=B9=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/Editor.razor.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js index f16d9c47..74448f8b 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js @@ -225,6 +225,12 @@ export function dispose(id) { } } +const createImage = file => { + const element = document.createElement('img'); + element.src = URL.createObjectURL(file); + return element; +} + const offEvent = eventEl => { if (eventEl) { EventHandler.off(eventEl, 'click') From f810debfd67034273faee57d89554789fbbd7215 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 13:16:41 +0800 Subject: [PATCH 5/9] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20ImageUploa?= =?UTF-8?q?d=20=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/Editor.razor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js index 74448f8b..d06c6b81 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js @@ -145,7 +145,7 @@ export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginI } const reloadCallbacks = (id, option) => { - const events = ['Blur', 'BlurCodeview', 'Change', 'ChangeCodeview', 'DialogShown', 'Enter', 'Focus', 'ImageLinkInsert', 'ImageUploadError', 'Init', 'Keydown', 'Keyup', 'Mousedown', 'Mouseup', 'Paste', 'Scroll']; + const events = ['Blur', 'BlurCodeview', 'Change', 'ChangeCodeview', 'DialogShown', 'Enter', 'Focus', 'ImageUpload', 'ImageLinkInsert', 'ImageUploadError', 'Init', 'Keydown', 'Keyup', 'Mousedown', 'Mouseup', 'Paste', 'Scroll']; events.forEach(event => { option.callbacks[`on${event}`] = function () { From 8bc2ab46aa095187a0e114f34e13942d319a030d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 14:14:29 +0800 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20SaveToFile?= =?UTF-8?q?Async=20=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/EditorUploadFileExtensions.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/components/BootstrapBlazor.SummerNote/Extensions/EditorUploadFileExtensions.cs diff --git a/src/components/BootstrapBlazor.SummerNote/Extensions/EditorUploadFileExtensions.cs b/src/components/BootstrapBlazor.SummerNote/Extensions/EditorUploadFileExtensions.cs new file mode 100644 index 00000000..c2bd7e5a --- /dev/null +++ b/src/components/BootstrapBlazor.SummerNote/Extensions/EditorUploadFileExtensions.cs @@ -0,0 +1,65 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// EditorUploadFile 扩展方法类 +/// +public static class EditorUploadFileExtensions +{ + /// + /// 保存到文件方法 + /// + /// + /// + /// + /// + /// + public static async Task SaveToFileAsync(this EditorUploadFile upload, string fileName, int bufferSize = 64 * 1024, CancellationToken token = default) + { + var ret = false; + + // 文件保护,如果文件存在则先删除 + if (File.Exists(fileName)) + { + try + { + File.Delete(fileName); + } + catch (Exception ex) + { + upload.Error = ex; + return ret; + } + } + + var folder = Path.GetDirectoryName(fileName); + if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + using var uploadFile = File.OpenWrite(fileName); + try + { + // 打开文件流 + var buffer = new byte[bufferSize]; + int bytesRead = 0; + + // 开始读取文件 + while ((bytesRead = await upload.Stream.ReadAsync(buffer, token)) > 0) + { + await uploadFile.WriteAsync(buffer.AsMemory(0, bytesRead), token); + } + ret = true; + } + catch (Exception ex) + { + upload.Error = ex; + } + + return ret; + } +} From 7222d128b61cb40406467ed7da7d3ee562fc99e4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 14:14:44 +0800 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20EditorUplo?= =?UTF-8?q?adFile=20=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/EditorUploadFile.cs | 103 ++---------------- 1 file changed, 12 insertions(+), 91 deletions(-) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs b/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs index 3e203351..37178e1c 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/EditorUploadFile.cs @@ -5,111 +5,32 @@ namespace BootstrapBlazor.Components; /// -/// 文件信息 +/// Editor 上传文件信息类 /// -public class EditorUploadFile +public class EditorUploadFile(string fileName, string contentType, long fileSize, Stream stream) { /// - /// 文件名 + /// 获得/设置 文件名 /// - public string? FileName { get; set; } + public string FileName => fileName; /// - /// 文件大小 + /// 获得/设置 文件大小 /// - public long FileSize { get; set; } + public long FileSize => fileSize; /// - /// 最后修改日期 + /// 获得/设置 文件类型 /// - public string? LastModified { get; set; } + public string ContentType => contentType; /// - /// 文件类型 + /// 获得/设置 上传的文件流 /// - public string? ContentType { get; set; } + public Stream Stream => stream; /// - /// 上传的文件流 + /// 获得/设置 错误信息 /// - public Stream? UploadStream { get; set; } - - /// - /// 文件索引 - /// 用于标识文件在上传列表中的位置 - /// 例如在上传多个文件时可以通过此属性区分每个文件的索引位置 - /// - public int Index { get; set; } - - /// - /// 返回码,0为成功,非0失败 - /// - public int Code { get; set; } - - /// - /// 错误信息 - /// - public string? Error { get; set; } - - /// - /// 保存到文件 - /// - /// - /// - /// - public async Task SaveToFile(string fileName, CancellationToken token = default) - { - var ret = false; - if (UploadStream != null) - { - // 文件保护,如果文件存在则先删除 - if (System.IO.File.Exists(fileName)) - { - try - { - System.IO.File.Delete(fileName); - } - catch (Exception ex) - { - Code = 1002; - Error = ex.Message; - } - } - - var folder = Path.GetDirectoryName(fileName); - if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder)) - { - Directory.CreateDirectory(folder); - } - - if (Code == 0) - { - using var uploadFile = File.OpenWrite(fileName); - - try - { - // 打开文件流 - var stream = UploadStream; - - var buffer = new byte[4 * 1096]; - int bytesRead = 0; - - // 开始读取文件 - while ((bytesRead = await stream.ReadAsync(buffer, token)) > 0) - { - await uploadFile.WriteAsync(buffer.AsMemory(0, bytesRead), token); - - } - ret = true; - } - catch (Exception ex) - { - Code = 1003; - Error = ex.Message; - } - } - } - return ret; - } - + public Exception? Error { get; set; } } From 231e9e23224ef41cb86fb33eed040791349bc98e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 14:15:22 +0800 Subject: [PATCH 8/9] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E5=87=8F=E5=B0=91=E4=B8=80=E6=AC=A1=20JS=20=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E5=BC=80=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Editor/Editor.razor.cs | 31 ++++++------------- .../Components/Editor/Editor.razor.js | 29 +++++++---------- 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs index b9c5be77..afc42478 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.cs @@ -64,7 +64,7 @@ public partial class Editor /// 获得/设置 Editor 组件内上传文件时回调此方法 /// [Parameter] - public Func>? OnFileUpload { get; set; } + public Func? OnFileUpload { get; set; } private bool _lastShowSubmit = true; @@ -265,30 +265,19 @@ public async Task ClickPluginItem(string pluginItemName) /// /// 文件上传回调 /// - /// + /// + /// + /// + /// [JSInvokable] - public async Task ImageUpload(EditorUploadFile uploadFile) + public async Task ImageUpload(string name, string contentType, long size, IJSStreamReference stream) { -#if NET6_0_OR_GREATER - var ret = ""; - if (Module != null) + var data = await stream.OpenReadStreamAsync(size); + var file = new EditorUploadFile(name, contentType, size, data); + if (OnFileUpload != null) { - var stream = await InvokeAsync("fetch", Id, uploadFile.Index); - if (stream != null) - { - using var data = await stream.OpenReadStreamAsync(); - uploadFile.UploadStream = data; - if (OnFileUpload != null) - { - ret = await OnFileUpload(uploadFile); - } - } + await OnFileUpload(file); } - return ret; -#else - await Task.Yield(); - throw new NotSupportedException(); -#endif } /// diff --git a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js index d06c6b81..0a0c4cb6 100644 --- a/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js +++ b/src/components/BootstrapBlazor.SummerNote/Components/Editor/Editor.razor.js @@ -47,21 +47,21 @@ export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginI option.toolbar = toolbar; reloadCallbacks(id, option); if (hasUpload) { - option.callbacks.onImageUpload = function (files) { + option.callbacks.onImageUpload = async files => { editor.files = files for (let i = 0; i < files.length; i++) { const file = files[i]; - editor.invoker.invokeMethodAsync('ImageUpload', { - fileName: file.name, - fileSize: file.size, - contentType: file.type, - lastModified: new Date(file.lastModified).toISOString(), - index: i - }).then(data => { - if (data !== "") { - editor.$editor.summernote('insertImage', data, file.name) - } - }) + const image = createImage(file); + editor.$editor.summernote('insertNode', image); + + const buffer = await file.arrayBuffer(); + const stream = DotNet.createJSStreamReference(buffer); + await editor.invoker.invokeMethodAsync('ImageUpload', + file.name, + file.type || 'application/octet-stream', + file.size, + stream + ) } } } @@ -166,11 +166,6 @@ export function update(id, val) { } } -export function fetch(id, index) { - const md = Data.get(id) - return md.files[index] -} - export function invoke(id, method, parameter) { const editor = Data.get(id) editor.$editor.summernote(method, ...parameter) From d9189d960d4ab2c2eb181fb88460cceffabe1f57 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 18 Aug 2025 14:15:58 +0800 Subject: [PATCH 9/9] chore: bump version 9.0.5 --- .../BootstrapBlazor.SummerNote.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/BootstrapBlazor.SummerNote/BootstrapBlazor.SummerNote.csproj b/src/components/BootstrapBlazor.SummerNote/BootstrapBlazor.SummerNote.csproj index 6a7a2619..bd3df802 100644 --- a/src/components/BootstrapBlazor.SummerNote/BootstrapBlazor.SummerNote.csproj +++ b/src/components/BootstrapBlazor.SummerNote/BootstrapBlazor.SummerNote.csproj @@ -1,7 +1,7 @@ - 9.0.4 + 9.0.5