XYS.FRCore 4.3.0

dotnet add package XYS.FRCore --version 4.3.0
                    
NuGet\Install-Package XYS.FRCore -Version 4.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="XYS.FRCore" Version="4.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="XYS.FRCore" Version="4.3.0" />
                    
Directory.Packages.props
<PackageReference Include="XYS.FRCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add XYS.FRCore --version 4.3.0
                    
#r "nuget: XYS.FRCore, 4.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package XYS.FRCore@4.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=XYS.FRCore&version=4.3.0
                    
Install as a Cake Addin
#tool nuget:?package=XYS.FRCore&version=4.3.0
                    
Install as a Cake Tool

XYS.FRCore

FastReport.Core 渲染宿主。只负责:拿 XYS.FRXYS.FR.V3 项目)准备好的 DataSet 与模板路径,调用 FastReport.Core 引擎导出 PDF/JPG/HTML/XLSX 流。不含数据契约与配置解析(实体注册、FRTables.frd 生成、模板号映射都在 XYS.FR 里),也不含打印(见下)。

  • 目标框架:net462 / netstandard2.0 / netcoreapp3.1 / net8.0
  • 报表引擎:FastReport.Core版本按目标框架分流(见下)
  • 依赖:XYS.FR.V3(传递带入 XYS.Utils.SysXYS.Utils.Log4Net
  • 程序集名:XYS.FRCore;命名空间 XYS.FR

⚠️ 当前引用的是 Demo 版 FastReport 包,导出结果带演示水印、有页数限制。正式部署需替换为已授权的 FastReport.Core 包(仅需改 PackageReference,代码无需改动)。

与 XYS.FRNet 的分工

XYS.FRCore(本项目) XYS.FRNet
引擎 FastReport.Core(跨平台版) FastReport.Net(完整版)
目标框架 net462 / netstandard2.0 / netcoreapp3.1 / net8.0 net462 / net8.0-windows
导出流
直接打印 ❌ 不实现 IFRPrintService ✅ 实现 IFRPrintService

两者的服务基类 API 形状刻意保持一致(ExportStream + ConfigureExport + ExportType 分发),便于在两个引擎间迁移。

不提供打印

BaseFRCoreService 不实现 IFRPrintService,本项目里根本没有 Print 方法。

原因:FastReport.Core 是跨平台版,不含任何打印 API —— 已核实 2023.3.13 版中 Report.Print()Report.PrintPrepared()PrintSettings 类型全部不存在(这些依赖 System.Drawing.Printing / WinForms)。

打印须由宿主完成:先用 ExportStream 导出 PDF,再交给宿主的打印组件。本解决方案中由 XYS.FRCore.PrintWinServicePrintIt.Core(Pdfium)打印。若需要 FastReport 直接打印,请改用 XYS.FRNet

4.0.0 时 PrintIFRService / BaseFRService 的抽象成员,本项目只能"实现了但恒抛 NotSupportedException",属 Liskov 违例。XYS.FR 4.1.0 把 IFRService 拆成 IFRExportService + IFRPrintService 后,本项目直接不声明打印接口,该违例已消除。

核心类型

类型 职责
BaseFRCoreService 抽象渲染服务基类,实现 BaseFRServiceExportStream

BaseFRCoreService 是本项目唯一的公开类型。

快速使用

using System;
using System.Collections.Generic;
using System.IO;
using XYS.FR;

public sealed class LabExportService : BaseFRCoreService
{
    public LabExportService()
    {
        LoggerName = "LabExportService";
        ActualType = typeof(LabExportService);
        Init();                              // 注册实体 + 生成 frd + 加载配置,放在构造函数末尾
    }

    protected override List<Type> GetFRTypes() => new List<Type>
    {
        typeof(FRInfo),
        typeof(FRItem),
    };

    protected override void InitFRConfig()
    {
        var cfg = new XmlConfigManager();    // 默认 AppBase/Config/fr.config.xml
        cfg.Init();                          // 失败抛异常,视为致命错误
        ConfigManager = cfg;
    }
}
var svc = new LabExportService();
var report = new FRReport { ModelNo = "LAB001", RID = "R123" };
report.Items.Add(new FRInfo { ID = "1", RID = "R123", PatName = "张三" });

using (var fs = File.Create("out.pdf"))
{
    svc.ExportStream(report, fs, ExportType.Pdf);
}

导出格式映射

ExportType 导出器 默认设置(ConfigureExport
Pdf PDFExport HideWindowUI=trueEmbeddingFonts=trueAllowModify=false
Jpg ImageExportImageFormat=Jpeg SeparateFiles=false
Html HTMLExport SinglePage=trueEmbedPictures=trueNavigator=false
Xls Excel2007Export

默认设置只保证单流输出这一底线语义:图片/HTML 导出若不关掉分文件,FastReport 只会把首页写进 Stream,其余页和图片会散落成流外的独立文件。

重写 ConfigureExport 可定制签名、分辨率、压缩等,建议先调 base

关键契约

成员 语义
ExportStream(FRReport, Stream, ExportType) 渲染到调用方提供的流;负责创建或释放该流
ExportStreamAsync(FRReport, Stream, ExportType, CancellationToken) 同上,可取消;排队等待限流的过程一定可取消,渲染阶段视 TFM 而定(见下)
Print 不存在:本类不实现 IFRPrintService,见上文
ConfigureExport(ExportBase, ExportType) virtual 扩展点
MaxConcurrentRendersstatic 并发渲染上限,默认 Min(核数, 4);见「并发限流」
异常 参数为 nullArgumentNullException;未知 ExportTypeArgumentOutOfRangeException;取消抛 OperationCanceledException;渲染异常记日志后原样上抛(保留堆栈)

ExportStream 无状态:每次调用独立取空数据集副本、独立 new Report(),同一实例可并发调用(并发度受 MaxConcurrentRenders 限制)。

并发限流

BaseFRCoreService 内置一个进程级 SemaphoreSlim,默认放行 Min(Environment.ProcessorCount, 4) 个并发渲染。

限流的理由是防塌,不是控吞吐。 2026-09-04 实测(FastReport 2025.2.8-demo,32 核,三轮一致):

线程数 1 2 4 8 16
相对单线程吞吐 1.00x 1.6–1.9x 2.0–2.4x 1.8–2.2x 0.39–0.48x

三个结论:引擎只能并行到 2 倍上下,4 线程就到顶,堆核没用;超订会塌,16 线程比单线程还慢一倍以上,且是"越忙越慢"的正反馈,一次并发高峰就能把渲染打进这个区间再也出不来;单份约 13 ms。

服务端跑在 ASP.NET 里,请求并发度由外部流量决定,没有限流就等于把渲染暴露在任意并发下。

本次改动后在同一台 32 核机器上复测(限流生效):

场景 吞吐
4 线程 171.9 份/秒
16 线程(上限 4) 193.4 份/秒
16 线程(上限调到 16,等于不限流) 110.6 份/秒 = 前者的 0.57x

即:限流后 16 线程不再掉进塌陷区,而把闸门打开就立刻重现了文档里的塌陷。

调整上限:

BaseFRCoreService.MaxConcurrentRenders = 8;   //宿主启动时设定一次
  • 信号量必须是 static——竞争在 FastReport 引擎内部,是进程级的。每个服务实例各持一个等于没限,宿主注册多个渲染服务时尤其明显。
  • 调整上限会重建信号量,只对调整之后进入的渲染生效;已在途的那几份仍按取得时的信号量释放,因此切换瞬间在途数可能短暂超过新上限。
  • 客户端侧(XYS.FRNet)不需要限流——单用户交互,不存在并发风暴。

异步与取消

await service.ExportStreamAsync(report, stream, ExportType.Pdf, ct);
阶段 能否被 ct 中断
排队等待限流 (全部 TFM)
渲染(Prepare net462 / net8.0 Report.PrepareAsync(ct));netcoreapp3.1 / netstandard2.0 不能
导出(Export 不能(FastReport 无异步导出 API)

netcoreapp3.1 / netstandard2.0 用的 FastReport.Core 2023.3.13 没有 PrepareAsync(2025.2.8 才有),只能退回"丢弃结果式取消"。这个差异由 csproj 里的 FR_PREPARE_ASYNC 编译开关控制,它与 FastReport 版本分流写在同一处条件,改版本时不会漏改。

FastReport.Core 版本分流

FastReport.Core 2025.2.8-demo 只提供 net462 / net6.0 / net6.0-windows7.0,没有 netcoreapp3.1netstandard2.0 的 lib,因此不能统一到单一版本

目标框架 FastReport.Core
net462net8.0 2025.2.8-demo
netcoreapp3.1netstandard2.0 2023.3.13-demo

csproj 中另显式钉住了 FastReport.Compat 2025.2.8FastReport.DataVisualization 2025.2.8。原因:FastReport.Core 2025.2.8-demo 的 nuspec 声明依赖这两个包的 2025.2.8-demo 版本,但它们不存在 -demo 后缀的版本,NuGet 只能回退推断到稳定版并对每个 TFM 报 NU1603。显式钉版后告警消失,而实际解析结果不变。

改动本项目的 TargetFrameworks 时,务必同步检查所选 FastReport.Core 版本是否提供对应的 lib。

4.3.0 变更(相对 4.2.0)

  • 模板改走 BaseFRService.OpenModel 取内容流(不再拼磁盘路径),模板可来自对象存储;日志里的模板标识随之改为"编号(文件名)"
  • 新增 ExportStreamAsync,重写基类默认实现:net462 / net8.0Report.PrepareAsync(ct) 做真取消
  • 新增进程级并发限流 MaxConcurrentRenders,默认 Min(核数, 4)
  • 静态构造补齐脚本沙箱:EnableScriptSecurity + ForbidLocalDataWebMode 本就已开)
  • csproj 新增 FR_PREPARE_ASYNC 编译开关,与 FastReport 版本分流同处一地

关于安全开关

模板将来由实施和客户编辑,也就是不可信输入;FastReport 模板能内嵌脚本,脚本可执行就等于客户能把代码送进服务端进程。

实测(FastReport.Core 2025.2.8-demo,模板内嵌 File.WriteAllText):

配置 结果
全关 脚本照跑,文件真的写出来了
只开 EnableScriptSecurity 脚本照跑(官方摘要 "For WebMode only" 属实)
WebMode 编译期即被拒:CS0117: Please, don't use the method 'WriteAllText'

所以真正起作用的是 WebMode,本项目原本就开着。EnableScriptSecurity 在其上追加禁用名单,默认为 DllImport / LoadLibrary / GetProcAddress(即 P/Invoke 出逃这一路),开启时由 FastReport 自动填充,无须再调 ScriptSecurityProps.SetDefaultStopList()

ForbidLocalData 的官方摘要是"不允许在 Xml 和 Csv 中指定本地数据路径"——它只管 Xml/Csv 的本地数据路径,挡不住模板内嵌的数据库连接。这只是一层,不是全部;真正的保障是渲染入口只吃 FRReport.Items 传进来的数据。

4.2.0 变更(相对 4.1.0)

  • 新增目标框架 net8.0
  • net462net8.0 的 FastReport.Core 升到 2025.2.8-demo;netcoreapp3.1netstandard2.0 保持 2023.3.13-demo(该版本无这两个 TFM 的 lib)
  • 四个按 TFM 拆分的条件 ItemGroup 合并为两个
  • 显式钉住 FastReport.Compat / FastReport.DataVisualization 稳定版,消除 16 条 NU1603

4.1.0 变更(相对 4.0.0)

破坏性

  • 跟随 XYS.FR 4.1.0 的接口拆分,BaseFRCoreService.Print(...) 整块删除。该方法在 4.0.0 中恒抛 NotSupportedException,从无可用调用方。
  • 本类现在只实现 IFRExportService(经 BaseFRService),不声明 IFRPrintService

4.0.0 变更(相对 3.0.1)

破坏性

  • BaseStreamService 更名为 BaseFRCoreService,与 XYS.FRNetBaseFRNetService 对称
  • 泛型导出方法 ExportStream<T> 删除,改为按 ExportType 枚举分发的 ExportStream(FRReport, Stream, ExportType)
  • protected abstract void SetExport(ExportBase)protected virtual void ConfigureExport(ExportBase, ExportType),由 abstractvirtual
  • 依赖由 FastReport.Core 2021.4.16-demo 升到 2023.3.13-demo;目标框架 netstandard2.1 换为 netcoreapp3.1(与该包实际提供的 TFM 一致)
  • 由 NuGet XYS.FR 改为 ProjectReference ..\XYS.FR.V3,与解决方案统一

修复

  • 项目此前无法编译ExportType.pdf 大小写未跟随 XYS.FR 4.0.0 的 PascalCase 改名(CS0117);ExportStreamoverride 隐藏基类抽象成员(CS0533);方法体残留已删除的泛型参数 new T()
  • throw ex; 丢失堆栈:改为 throw;
  • Config.WebMode 每次导出都重设:它是进程级全局配置,移入静态构造函数只设一次
  • catch 块内可能二次抛 NRE:日志用 ActualType.FullName,子类未设 ActualType 时会 NRE 并掩盖真实异常,现回退到运行时类型名
  • 图片/HTML 导出丢页:单 Stream 输出下未关 SeparateFiles / 未开 EmbedPictures,只有首页进流

清理

  • MethodBase.GetCurrentMethod().Name 反射取名 → nameof
  • README 从残桩重写(原文写"FastReport Core 2021 版本集成",实际引用 2023.3.13)

注意事项

  • 多目标下语言版本不一致net462 / netstandard2.0 默认 C# 7.3,netcoreapp3.1 默认 C# 8。本项目代码按 C# 7.3 编写,刻意避开 switch 表达式等 C# 8+ 语法。
  • 完整版 FastReport .NET 的 ReportSettings.ShowProgress / ShowPerformanceWinForms 专属属性,Core 版的 ReportSettings 不含它们(Core 无进度 UI,本就无需关闭)。
  • Init() 放在子类构造函数末尾
  • 同进程内允许多个子类共存,共享 XYS.FRDataStruct 实体注册表。
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.1 is compatible. 
.NET Framework net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.3.0 106 9/5/2026
4.2.0 109 9/4/2026
4.1.0 91 9/4/2026
2.1.0.6 699 9/14/2022
2.1.0.5 567 9/13/2022
2.1.0.4 567 8/4/2022
2.0.0.3 552 8/4/2022