Генерация / отправка вложенных файлов в формате PDF в рамках задания зависания

В нашем веб-приложении ASP.NET MVC мы отправляем электронные письма как часть запланированных задач, выполняемых Hangfire, для которых я использую почтовую службу, как описано здесь. Метод отлично работает, и мы можем отправлять электронные письма в формате HTML/ текст. Теперь нам нужно сгенерировать и прикрепить PDF-файлы. Прикрепленный PDF-файл необходимо генерировать динамически с помощью шаблона Razor. Сначала я попытался использовать Rotativa для создания PDF. Однако я столкнулся с проблемой, что метод BuildPdf требует ControllerContext, который не доступен в фоновом процессе HangFire. Я попытался подделать ControllerContext как

using (var memWriter = new StringWriter(sb))
            {

                var fakeResponse = new HttpResponse(memWriter);

                var fakeRequest = new HttpRequest(null, "http://wwww.oururl.com", null);
                var fakeHttpContext = new HttpContext(fakeRequest, fakeResponse);
                var emailController = new BackgroundEmailController();
                var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeHttpContext), new RouteData(), emailController);

                var attachment = emailController.BillAttachment(email);

                var pdf = attachment.BuildPdf(fakeControllerContext);

                if (pdf != null && pdf.Count() > 0)
                {
                    using (MemoryStream ms = new MemoryStream(pdf))
                    {
                        var contentType = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf);
                        email.Attach(new System.Net.Mail.Attachment(ms, contentType));
                    }
                }
            }              

Однако это вызвало ошибку NullReference в Rotativa. Затем я попытался сначала скомпилировать представление шаблона с помощью RazorEngine в HTML(а затем каким-то образом преобразовать HTML в pdf) как

var engineService = RazorEngineService.Create();

            engineService.AddTemplate(cache_name, File.ReadAllText(billAttachmentTemplatePath));
            engineService.Compile(cache_name, modelType: typeof(BillEmail));
            var html = engineService.Run(cache_name, null, email);

            using (var ms = CommonHelper.GenerateStreamFromString(html))
            {
                var contentType = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Html);
                email.Attach(new System.Net.Mail.Attachment(ms, contentType));
            }

И он выбрасывает еще одну NullReference в динамическую DLL RazorEngine:

 System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_bb2b366aaef64f2bbc2997353f88cc9e.Execute()
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)

Мне было интересно, есть ли у кого-нибудь предложения для создания PDF-файлов из шаблона в процессе Hangfire?

1 ответ

Если вы открыты для коммерческих решений, вы можете попробовать Telerik отчетности и экспортировать ее в формате PDF программно. Вы определяете свой отчет, а затем вызываете его для генерации PDF на стороне сервера и, наконец, отправляете байт по электронной почте в виде вложения электронной почты. Теперь вы можете запустить этот процесс с помощью задания Hangfire.

Вот псевдокод, предполагающий, что вы определили структуру своего отчета. Пожалуйста, посмотрите здесь более подробную информацию о том, как создать свой отчет программно.

public void GenerateAndEmailReport()
{     
    var reportSource = new InstanceReportSource();
    Telerik.Reporting.Report report = new MyReport();

    //populate data into report

    reportSource.ReportDocument = report;

    var reportProcessor = new ReportProcessor();
    reportSource.ReportDocument = report;
    var info = new Hashtable();
    var result= reportProcessor.RenderReport("PDF", reportSource, info);

    byte[]reportBytes = result.DocumentBytes;

    SendEmail(reportBytes, "myreport.pdf"); // a method that takes the bytes and attach it to email. 
}

Дополнительные ссылки от телерика.

Другие вопросы по тегам