.Net Core在线预览打印PDF,JsReport的使用

2021-01-27

说到在线预览并打印Pdf,Java的解决方案可谓层出不穷,尤以JasperReport为甚,再加上各大博客的资源分享,实现其功能更是易如反掌。再看回c#,资源寥寥无几,大多数是根据一个pdf模板,再生成一个新的pdf。

出去上网看了一下,终于找到解决方案:jsreport

在线预览Demo:jsreport playground

社区论坛:jsreport forum

基础文档:Learn jsreport

image-20210127113926999

三大特征:

  1. 可支持生成多种文件类型(pdf, excel, docx, html, csv)

  2. 开源、跨平台(用于商业可购买)

  3. html为模板(JasperReport以xml为模板,个人还是比较习惯用html的...)

    基本介绍完之后,那么该如何在dotnet Core中使用呢?

jsreport: dotnet文档

image-20210127114617254

Startup.cs的ConfigureServices加入:

Controller加一个Action

对应的View:

Action头部添加jsreport特性:[MiddlewareFilter(typeof(JsReportPipeline))]

返回视图前也要添加:HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf);

View视图层就是pdf生成的模板,里面的数据可动态变化,只需传入对应的ViewModel即可。数据可动态变化,我们可以根据数据生成文档(pdf),而不需要每一份文档都存储到服务器里面,在预览合同、打印标签等场景下非常适用。

效果预览图:

image-20210127141611552

如何预览并在程序中保存文档:

适用于发送邮件时发送附件或将文档存储到服务器的场景

值得注意的是:如果你的程序(常出现在web api项目)使用ActionFilterAttribute来过滤返回的结果集,要将当前预览pdf的Action排除出去,不然会出现生成不了pdf或者pdf内容不正确的情况。

image-20210127144750553

改动后

image-20210127145517534

补充:

错误一:

2021-02-08 10:45:31.6101 | Error | Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer | Connection ID "17437937767379108040", Request ID "800000c9-0002-f200-b63f-84710c7967bb": An unhandled exception was thrown by the application. jsreport.Local.JsReportBinaryException: Error rendering report: A critical error occurred while trying to execute the render command (2). An error occurred while trying to start daemonized process: An error has occurred when trying to initialize jsreport (1). caused by error (2):-> stackError: at onCriticalError (D:\snapshot\jsreport\node_modules\jsreport-cli\lib\commands\render.js:302:19) at D:\snapshot\jsreport\node_modules\jsreport-cli\lib\commands\render.js:256:14caused by error (1):-> meta = {"code":"EACCES"}-> stackError: An error has occurred when trying to initialize jsreport at Object. (D:\snapshot\jsreport\node_modules\jsreport-cli\lib\keepAliveProcess.js:158:27) at Object.listener (D:\snapshot\jsreport\node_modules\eventemitter2\lib\eventemitter2.js:251:10) at Object.emit (D:\snapshot\jsreport\node_modules\eventemitter2\lib\eventemitter2.js:339:22) at Object.onData (D:\snapshot\jsreport\node_modules\nssocket\lib\nssocket.js:454:8) at Lazy. (D:\snapshot\jsreport\node_modules\lazy\lazy.js:91:13) at Lazy. (D:\snapshot\jsreport\node_modules\lazy\lazy.js:73:19) at Lazy.emit (events.js:311:20) at Lazy. (D:\snapshot\jsreport\node_modules\lazy\lazy.js:74:22) at Lazy.emit (events.js:311:20) at yieldTo (D:\snapshot\jsreport\node_modules\lazy\lazy.js:181:18)Remote Instance Error: Error: at D:\snapshot\jsreport\node_modules\jsreport-cli\lib\instanceHandler.js:31:29Remote Instance Error: Error: at Server.setupListenHandle [as _listen2] (net.js:1292:21) at listenInCluster (net.js:1357:12) at Server.listen (net.js:1445:7) at D:\snapshot\jsreport\node_modules\jsreport-express\lib\reporter.express.js:23:12 at Promise.execute (D:\snapshot\jsreport\node_modules\bluebird\js\release\debuggability.js:313:9) at Promise._resolveFromExecutor (D:\snapshot\jsreport\node_modules\bluebird\js\release\promise.js:483:18) at new Promise (D:\snapshot\jsreport\node_modules\bluebird\js\release\promise.js:79:10) at startAsync (D:\snapshot\jsreport\node_modules\jsreport-express\lib\reporter.express.js:17:10) at D:\snapshot\jsreport\node_modules\jsreport-express\lib\reporter.express.js:51:14 at Object.start (D:\snapshot\jsreport\node_modules\jsreport-express\lib\reporter.express.js:125:13) at Object. (D:\snapshot\jsreport\node_modules\jsreport-express\lib\reporter.express.js:317:30) at jsreport.Local.Internal.LocalUtilityReportingService.RenderAsync(String requestString, CancellationToken ct) at jsreport.AspNetCore.JsReportMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gLogged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.gAwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\projects\dotnet\src\MiniProfiler.AspNetCore\MiniProfilerMiddleware.cs:line 103 at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT1.ProcessRequestAsync() AsyncStateMachineBox1.ExecutionContextCallback => d__2.MoveNext => IISHttpContext.ReportApplicationError

 

解决方案:端口被占用,切换为可用端口(如:8018)即可,如果是发布到服务器上要在服务器管理后台上开放指定端口(如:8018)

image-20210208105526147

image-20210208105120757

查看源码:.Net Core在线预览打印PDF,JsReport的使用