界面组件DevExpress中文教程 - 如何在Node.js应用中创建报表?

DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表。

获取DevExpress Reporting最新正式版下载(Q技术交流:532598169)

为什么选择Node.js和WebAssembly?

自定义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文件。

开始前
  • 安装 .NET 8 SDK。
  • 安装最新的CLI模板:

>dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates::8.0.3

  • 安装wasm-tools工作负载:

>dotnet workload install wasm-tools

创建一个简单的Wasmconsole应用

运行以下命令创建一个示例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报表

对于未安装DevExpress的macOS/Linux或Windows操作系统,请执行以下操作:

  • 创建一个nuget.config文件:

dotnet new nugetconfig

  • 删除nuget.config文件中的“clear /”
  • 更新add key="nuget" value="https://api.nuget.org/v3/index.json" ,并将nuget键替换为自定义提要名称,并将该值替换为从DevExpress NuGet Gallery页面获得的DevExpress NuGet Feed URL。

完成后,安装在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中运行该程序集。

.NET解决方案

在您喜欢的代码编辑器中打开文件夹,在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对象,使用XtraReport.ExportToPdfAsync方法将报表导出为PDF。

JsonSourceCustomizationService

这个服务取代了JsonDataSource.JsonSource值,使用满足Blazor限制的自定义对象。这是因为WebAssembly不允许HTTP请求,而报表模型可能会引用带有URI的JSON源。

SimplifiedUriJsonSource

该类是UriJsonSource类的后代,并将HTTP请求重定向到应用程序的javascript段。

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();

该文件中的代码:

  • 在WASM中配置 .NET 运行时。
  • 导入getJsonData()函数来从URL检索JSON文件。
  • 调用并执行ExportToPdfAsync方法来生成PDF文档。
  • 使用本地Node.js函数保存生成的PDF文件。
查看结果

要运行应用程序,首先构建.NET应用程序,导航到result文件夹,然后运行JavaScript应用程序:

>dotnet build
>cd result
>node main.mjs

应用程序在结果目录中创建一个新的result.pdf文件。

使用DevExpress Web文档查看器和报表设计器

按照readme文件中列出的步骤,运行后端和客户端应用程序,并将浏览器指向客户端应用程序中指定的URL。结果将显示如下:

DevExpress XAF (WinForms UI)实用案例图


更多DevExpress线上公开课、中文教程资讯请上中文网获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/585967.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis-Plus扩展接口InnerInterceptor

InnerInterceptor 接口就是 MyBatis-Plus 提供的一个拦截器接口&#xff0c;用于实现一些常用的 SQL 处理逻辑&#xff0c;处理 MyBatis-Plus 的特定功能,例如PaginationInnerInterceptor、OptimisticLockerInnerInterceptor 等,都实现了 InnerInterceptor 接口&#xff0c;并添…

透视天气:数据可视化的新视角

数据可视化在天气方面能够为我们带来极大的帮助。天气是人类生活中一个重要的因素&#xff0c;对于农业、交通、航空、能源等各个领域都有着重要的影响。而数据可视化技术通过将复杂的天气数据转化为直观、易懂的图表、图像或地图等形式&#xff0c;为我们提供了更深入、更全面…

数据赋能(73)——数据要素:特征

生产要素中的数据要素具有一系列基本特征&#xff0c;这些特征使得数据在现代经济活动中发挥着越来越重要的作用。数据要素的主要特征如下图所示。 数据已经成为关键的生产要素&#xff0c;数据要素的基本特征可以概括为&#xff1a;虚拟性、非消耗性、非稀缺性、非均质性、排他…

移植USB RTL8723DU WIFI无线驱动给RK3588

wifi 通过dmesg发现可以识别到设备为无线网卡&#xff0c;并驱动蓝牙&#xff0c;但是在ifconfig中没有找到对应的wlan0。 推断有可能是内核里面没有针对8723du wifi的驱动。所以需要查询当前的5.10内核是否包含8723du的驱动。到https://linux-hardware.org/ 上查看。 并结合…

使用RTSP将笔记本摄像头的视频流推到开发板

一、在Windows端安装ffmpeg 1. 下载ffmpeg:下载ffmpeg 解压ffmpeg-master-latest-win64-gpl.zip bin 目录下是 dll 动态库 , 以及 可执行文件 ;将 3 33 个可执行文件拷贝到 " C:\Windows " 目录下 ,将所有的 " .dll " 动态库拷贝到 " C:\Windows\Sy…

linus下Anaconda创建虚拟环境pytorch

一、虚拟环境 1.创建 输入下面命令 conda create -n env_name python3.8 输入y 2.激活环境 输入 conda activate env_name 二、一些常用的命令 在Linux的控制平台 切换到当前的文件夹 cd /根目录/次目录 查看conda目录 conda list 查看pip目录 pip list查看历史命…

Springboot+Vue项目-基于Java+MySQL的教学资料管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

[游戏陪玩系统] 陪玩软件APP小程序H5游戏陪玩成品软件源码-线上线下可爆改家政,整理师等功能

简介 随着电竞行业的快速发展&#xff0c;电竞陪玩APP正在逐渐成为用户在休闲娱乐时的首选。为了吸引用户和提高用户体验&#xff0c;电竞陪玩APP开发需要定制一些特色功能&#xff0c;并通过合适的盈利模式来获得收益。本文将为您介绍电竞陪玩APP开发需要定制的特色功能以及常…

AI图书推荐:将 ChatGPT和Excel融合倍增工作效率

《将 ChatGPT和Excel融合倍增工作效率》&#xff08; Hands-on ChatGPT in Excel. Enhance Your Excel Workbooks&#xff09;由Mitja Martini撰写&#xff0c;旨在教授读者如何将ChatGPT与Excel结合使用&#xff0c;以提升工作效率和创造AI增强的Excel工具。它还提供了Excel中…

2024年Docker常用操作快速查询手册

目录 一、Linux系统上 Docker安装流程&#xff08;以ubuntu为例&#xff09; 一、卸载所有冲突的软件包 二、设置Docker的apt存储库&#xff08;这里使用的是阿里云软件源&#xff09; 三、直接安装最新版本的Docker 三、安装指定版本的Docker 四、验证Docker是否安装成功…

06_Flutter自定义锚点分类列表

06_Flutter自定义锚点分类列表 这样的效果&#xff0c;大家在一些商超应用里&#xff0c;应该也看到过。接下来咱们就用Flutter一步一步的来实现。 一.自定义属性抽取 categoryWidth: 左侧边栏的宽度&#xff0c;右侧区域的宽度填充剩余空间即可。itemCount: 总共有多少个分类…

Centos 系列 安装ArchR

Analyzing single-cell regulatory chromatin in R. • ArchRhttps://www.archrproject.com/ ArchR is a scalable software package for integrative single-cell chromatin accessibility analysis 一、Installation of ArchR &#xff08;Ideal&#xff09; ArchR is desig…

四川古力未来科技抖音小店安全:守护您的网购体验

在互联网购物日益普及的今天&#xff0c;四川古力未来科技抖音小店以其独特的魅力和安全保障措施&#xff0c;成为越来越多消费者信赖的购物平台。本文将为您详细解读四川古力未来科技抖音小店的安全保障措施&#xff0c;让您在享受便捷购物的同时&#xff0c;也能安心、放心。…

【简单讲解下FastStone Capture】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

首页最新 多IP浏览器防关联:如何配置多个独立且稳定的IP地址?

在互联网时代&#xff0c;IP地址的重要性不言而喻。然而&#xff0c;IP关联问题却成为一项令人担忧的隐私和安全挑战。针对这个问题&#xff0c;多IP浏览器是一种解决方案&#xff0c;可以帮助用户单独配置多个独立且稳定的IP地址&#xff0c;有效地防止IP关联。 一、IP关联是…

如何使用 ArcGIS Pro 查找小区最近的地铁站

学习 GIS 除了可以用在工作上之外&#xff0c;还可以将其运用到生活之中&#xff0c;比如查找距离小区最近的地铁站&#xff0c;这里为大家介绍一下查找的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的POI数据&#xff0c;除了POI数据…

【PyTorch与深度学习】4、PyTorch的Dataset与DataLoader详细使用教程

课程地址 最近做实验发现自己还是基础框架上掌握得不好&#xff0c;于是开始重学一遍PyTorch框架&#xff0c;这个是课程笔记&#xff0c;这个课还是讲的简略&#xff0c;我半小时的课听了一个半小时。 1. Dataset与DataLoader Dataset类是处理单个训练样本的&#xff0c;也就…

Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(2)vi discarding frame问题调试

基于上篇调试记录 Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(1)MIPI问题调试-CSDN博客 1.前言 当通过gstreamer持续捕获视频设备时,帧数会下降,并且I输入越高,丢失的帧数越多。 当达到4k30hz时,它完全无法使用,系统会在几秒钟的收集后崩溃并重新启动 4k30hz …

Stm32CubeMX 为 stm32mp135d 添加 adc

Stm32CubeMX 为 stm32mp135d 添加 adc 一、启用设备1. adc 设备添加2. adc 引脚配置2. adc 时钟配置 二、 生成代码1. optee 配置 adc 时钟和安全验证2. linux adc 设备 dts 配置 bringup 可参考&#xff1a; Stm32CubeMX 生成设备树 一、启用设备 1. adc 设备添加 启用adc设…

六氟化硫红外吸收峰

特此记录 anlog 2024年4月30日
最新文章