翻譯|使用教程|編輯:龔雪|2024-04-29 10:30:46.777|閱讀 108 次
概述:本文將為大家介紹如何通過.NET和WebAssembly集成如何在Node.js應用程序中創建報表,歡迎下載相關組件體驗!
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
DevExpress Reporting是.NET Framework下功能完善的報表平臺,它附帶了易于使用的Visual Studio報表設計器和豐富的報表控件集,包括數據透視表、圖表,因此您可以構建無與倫比、信息清晰的報表。
DevExpress技術交流群10:532598169 歡迎一起進群討論
自定義DevExpress報表(在后端應用程序中)可能會給剛接觸 .NET的前端Web開發人員帶來獨特的挑戰,在本文中我們將向您展示.NET和WebAssembly集成是如何幫助解決這些挑戰,并增強整體應用程序的安全性和性能的。
傳統的報表開發/定制方法需要 .NET和相關語言的專業知識,但WebAssembly消除了這個困難。通過在WASM環境中運行.NET應用程序,開發人員無需深入了解.NET就可以將交互式報表集成到Node.js應用程序中。
這種集成的第二個好處與安全性有關,WebAssembly在隔離的環境中執行代碼。因此開發人員可以完全控制磁盤、網絡和其他關鍵資源,這種隔離的執行環境可以降低與未授權訪問相關的風險。
Microsoft在最近的.NET更新中一直致力于 .NET 和WebAssembly的集成,在.NET 7中,Micrsooft引入了CLI模板(如wasmconsole和wasmbrowser),并允許開發人員創建在承載.NET運行時的沙盒WebAssembly環境中運行的控制臺和web應用程序。
隨著.NET 8的發布,應用程序代碼在編譯時直接轉換為WebAssembly,這一變化帶來了與性能相關的顯著改進,其特點是延遲減少、用戶界面響應更快。
如果您是一個剛接觸.NET的前端Web開發人員,并且對這篇內容感興趣,建議創建一個應用程序,允許創建DevExpress報表并將其導出為PDF文件。
>dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates::8.0.3
>dotnet workload install wasm-tools
運行以下命令創建一個示例wasm-export應用:
>dotnet new wasmconsole -o wasm-exporter
當示例項目準備好后,導航到項目文件夾:
>cd wasm-exporter
Program.cs文件包含以下代碼:
using System; using System.Runtime.InteropServices.JavaScript; Console.WriteLine("Hello, Console!"); return 0; public partial class MyClass { [JSExport] internal static string Greeting() { var text = $"Hello, World! Greetings from node version: {GetNodeVersion()}"; return text; } [JSImport("node.process.version", "main.mjs")] internal static partial string GetNodeVersion(); }
如您所見,JavaScript導入Greeting .NET函數,而.NET本身導入一個函數,該函數顯示當前安裝的Node.js版本。
反過來,代碼在main.mjs文件加載.NET運行時并將JavaScript函數導入WebAssembly:
import { dotnet } from './_framework/dotnet.js' const { setModuleImports, getAssemblyExports, getConfig } = await dotnet .withDiagnosticTracing(false) .create(); setModuleImports('main.mjs', { node: { process: { version: () => globalThis.process.version } } }); const config = getConfig(); const exports = await getAssemblyExports(config.mainAssemblyName); const text = exports.MyClass.Greeting(); console.log(text); await dotnet.run();
一旦您使用了dotnet build命令構建了這個應用程序,運行它的方式與您通常運行node.js應用程序的方式相同,來查看兩個函數的執行結果:
>dotnet build
>node main.mjs
Hello, World! Greetings from node version: v18.12.1
Hello, Console!
對于未安裝DevExpress的macOS/Linux或Windows操作系統,請執行以下操作:
dotnet new nugetconfig
完成后,安裝在WebAssembly應用程序中創建文檔所需的NuGet包:
dotnet add package Newtonsoft.Json dotnet add package DevExpress.Drawing.Skia --version 23.2.*-* dotnet add package DevExpress.Reporting.Core --version 23.2.*-* dotnet add package SkiaSharp.HarfBuzz --version 2.88.7 dotnet add package SkiaSharp.NativeAssets.WebAssembly --version 2.88.7 dotnet add package HarfBuzzSharp.NativeAssets.WebAssembly --version 2.8.2.4 dotnet add package SkiaSharp.Views.Blazor --version 2.88.7
在項目配置文件(wasm- exporters .csproj)中添加一個本地SkiaSharp依賴項:
<ItemGroup> <NativeFileReference Include="$(HarfBuzzSharpStaticLibraryPath)\2.0.23\*.a" /> </ItemGroup>
指定生成的可執行文件和庫的路徑:
<wasmappdir>./result</wasmappdir>
在這一點上,我們完成了準備工作,并準備開始編碼。
我們的應用程序由兩個部分組成:一個基于.NET服務器的應用程序編譯成程序集,一個JavaScript客戶端應用程序創建并配置.NET運行時環境,以便在WASM中運行該程序集。
在您喜歡的代碼編輯器中打開文件夾,在Program.cs代碼單元中實現以下類:ReportExporter、JsonSourceCustomizationService和SimplifiedUriJsonSource:
using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.Reflection; using System.Runtime.InteropServices.JavaScript; using System.Threading; using System.Threading.Tasks; using DevExpress.Data; using DevExpress.DataAccess.Json; using DevExpress.XtraPrinting; using DevExpress.XtraReports.UI; return 0; public partial class ReportExporter { [JSExport] internal static async Task ExportToPdfAsync(JSObject exportModel, JSObject result) { using var report = new XtraReport(); ((IServiceContainer)report).AddService(typeof(IJsonSourceCustomizationService), new JsonSourceCustomizationService()); using var reportStream = new MemoryStream(exportModel.GetPropertyAsByteArray("reportXml")); report.LoadLayoutFromXml(reportStream, true); PdfExportOptions pdfOptions = report.ExportOptions.Pdf; if(exportModel.HasProperty("exportOptions")) { SimplifiedFillExportOptions(pdfOptions, exportModel.GetPropertyAsJSObject("exportOptions")); } using var resultStream = new MemoryStream(); await report.ExportToPdfAsync(resultStream, pdfOptions); result.SetProperty("pdf", resultStream.ToArray()); resultStream.Close(); } static void SimplifiedFillExportOptions(object exportOptions, JSObject jsExportOptions) { PropertyInfo[] propInfos = exportOptions.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach(PropertyInfo pi in propInfos) { if(!jsExportOptions.HasProperty(pi.Name)) continue; if(pi.PropertyType == typeof(bool)) { pi.SetValue(exportOptions, jsExportOptions.GetPropertyAsBoolean(pi.Name)); } else if(pi.PropertyType == typeof(string)) { pi.SetValue(exportOptions, jsExportOptions.GetPropertyAsString(pi.Name)); } else if(pi.PropertyType.IsEnum) { string val = jsExportOptions.GetPropertyAsString(pi.Name); if(Enum.IsDefined(pi.PropertyType, val)) { pi.SetValue(exportOptions, Enum.Parse(pi.PropertyType, val)); } } else if(pi.PropertyType.IsClass) { SimplifiedFillExportOptions(pi.GetValue(exportOptions), jsExportOptions.GetPropertyAsJSObject(pi.Name)); } } } } public class JsonSourceCustomizationService : IJsonSourceCustomizationService { public JsonSourceBase CustomizeJsonSource(JsonDataSource jsonDataSource) { return jsonDataSource.JsonSource is UriJsonSource uriJsonSource ? new SimplifiedUriJsonSource(uriJsonSource.Uri) : jsonDataSource.JsonSource; } } public partial class SimplifiedUriJsonSource : UriJsonSource { public SimplifiedUriJsonSource(Uri uri) : base(uri) { } public override Task GetJsonStringAsync(IEnumerable sourceParameters, CancellationToken cancellationToken) { return GetJsonData(Uri.ToString()); } [JSImport("getJsonData", "main.mjs")] internal static partial Task GetJsonData(string url); }
ReportExporter
該類實現ExportToPdfAsync方法并將其導出到JavaScript模塊,該方法創建一個XtraReport實例,將JsonSourceCustomizationService自定義服務添加到報表對象模型,并將可選的導出選項從javascript對象映射到本地.NET對象,使用方法將報表導出為PDF。
JsonSourceCustomizationService
這個服務取代了值,使用滿足Blazor限制的自定義對象。這是因為WebAssembly不允許HTTP請求,而報表模型可能會引用帶有URI的JSON源。
SimplifiedUriJsonSource
該類是UriJsonSource類的后代,并將HTTP請求重定向到應用程序的javascript段。
main.mjs文件是應用程序的核心JS段,將其內容替換為以下代碼:
// Import necessary modules. import { dotnet } from '._framework/dotnet.js'; import fs from 'fs'; import { get as httpGet } from 'http'; import { get as httpsGet } from 'https'; import url from 'url' // Configure .NET runtime for WASM execution. const { setModuleImports, getAssemblyExports, getConfig } = await dotnet .withDiagnosticTracing(false) .create(); setModuleImports('main.mjs', { getJsonData }); // Retrieve the exported methods from the WASM part. const config = getConfig(); const exports = await getAssemblyExports(config.mainAssemblyName); // Prepare the report model and related options. const repx = fs.readFileSync('../reports/report1.repx'); const model = { reportXml: repx, exportOptions: { DocumentOptions: { Application: "WASM", Subject: "wasm integration" }, PdfUACompatibility: "PdfUA1" } } // Export the report to PDF. const result = {}; await exports.ReportExporter.ExportToPdfAsync(model, result); const buffer = Buffer.from(result.pdf); fs.writeFileSync('result.pdf', buffer); // Define a method to fetch JSON data from a given URL. function getJsonData(jsonUrl) { return new Promise((resolve) => { const fetchMethod = url.parse(jsonUrl).protocol === 'https:' ? httpsGet : httpGet; fetchMethod(jsonUrl, res => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(data)); }).on('error', err => resolve('')); }); } // Initiate the .NET runtime. await dotnet.run();
該文件中的代碼:
要運行應用程序,首先構建.NET應用程序,導航到result文件夾,然后運行JavaScript應用程序:
>dotnet build
>cd result
>node main.mjs
應用程序在結果目錄中創建一個新的result.pdf文件。
按照readme文件中列出的步驟,運行后端和客戶端應用程序,并將瀏覽器指向客戶端應用程序中指定的URL。結果將顯示如下:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:慧都網