繁体   English   中英

MVC ControllerContext、线程/任务、Rotativa

[英]MVC ControllerContext, Threads/Tasks, Rotativa

Rotativa 1.6.4 不断在 Rotativa.dll 中发出 System.NullReferenceException

具体来说,它发生在 BuildPdf(context) 上

我尝试过线程、任务和其他后台类型的工作。 为什么? PDF 生成有时非常慢,而且使用 ActionAsPdf(请参阅此处)有问题,所以我想将它分拆到一个新的线程/任务或后台作业,并且只记录错误,这样我就可以让用户尽快回到他们的路上。

BuildPdf 采用当前的控制器上下文,它总是为 null 我试过创建一个新的上下文,使用 httpcontext,创建一个新的控制器实例,所有的结果都相同。 一旦它进入 Rotativa.dll,上下文就完全消失了,无论我是在成为线程/任务之前传入它,还是在调用 BuildPdf() 之前创建一个新的;

如何在开始线程/任务作业之前或在线程/任务作业内部进入 Rotativa 时获取有效的控制器上下文?

在这一点上,我已经准备好在真正的 PDF 解决方案上花真钱了,但到目前为止,它们似乎都是 PITA,即使您对 PDF 有最简单的儿童需求,也只能算中等。

您是否尝试创建SynchronizationContext代替?

似乎该库是非线程安全的。

我正在处理同样的问题。 我尝试模拟 ControllerContext,使用 MvcContrib 创建 FakeControllerContexts(如在 Rotativa 单元测试库中所见)等......

为了从模型调用函数,我最终使用了 RazorEngine(以获取由模型数据填充的 html)+ iTextSharp(将 html 转换为 pdf)而不是 Rotativa。 这在我的项目(电子邮件、pdf 等)中创建了一个优雅的模板可能性。

using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.html.simpleparser;

...
public class PDFHelper { 
        public static byte[] GetPDFGromHTMLString(string pHTML) {
            byte[] bPDF = null;

            MemoryStream ms = new MemoryStream();
            TextReader txtReader = new StringReader(pHTML);

            // 1: create object of a itextsharp document class
            Document doc = new Document(PageSize.A4, 25, 25, 25, 25);

            // 2: we create a itextsharp pdfwriter that listens to the document and directs a XML-stream to a file
            PdfWriter oPdfWriter = PdfWriter.GetInstance(doc, ms);

            // 3: we create a worker parse the document
            HTMLWorker htmlWorker = new HTMLWorker(doc);

            // 4: we open document and start the worker on the document
            doc.Open();
            htmlWorker.StartDocument();

            // 5: parse the html into the document
            htmlWorker.Parse(txtReader);

            // 6: close the document and the worker
            htmlWorker.EndDocument();
            htmlWorker.Close();
            doc.Close();

            bPDF = ms.ToArray();

            return bPDF;
        }

在模型中,我将其用作:

using RazorEngine;
using RazorEngine.Templating;
...
string razorText = System.IO.File.ReadAllText(HostingEnvironment.MapPath(@"~/Views/MyReport.cshtml"));
string body = Razor.Parse(razorText, model);
byte[] pdfBinary = MyFramework.PDFHelper.GetPDFGromHTMLString(body);
/**other stuff */

如果您不想在 RazorEngine 中处理 RequestContext,则不应使用 Html 和 Url 助手(将 @Html.DisplayFor(model => ..) 更改为 @Model.MyProperty)

对于那些试图像我一样把它们弄出去的人...我尝试了一切,从使用DriverOptions在此描述)传递cookie到将ViewAsPdf生成的ViewAsPdf渲染为字符串(自定义Razor扩展)并转换到一个字节数组 - 但只是从ActionAsPdf更改为PartialViewAsPdf为我解决了它。

无论出于何种原因PartialViewAsPdf包含相同(或更好的/改善...?) BuildPdf(ControllerContext)方法ActionAsPdf ,但ViewAsPdf没有。 PartialViewAsPdf类在ControllerContext传递,并按照我的预期访问我的特定于上下文的变量。

试试这个!!

Task.Factory.StartNew(() =>                  
 {
     Do Something here
 },
 CancellationToken.None,
 TaskCreationOptions.PreferFairness,
 TaskScheduler.FromCurrentSynchronizationContext() 
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM