JsReport save action result in PDF

Viewed 434

I would like to generate the PDF based on the View, but I don't want to display it after generating it. Just save to disk.

As I am in Azure, I had to use the version with Docker, but it did not print the footer (page count)

With that I will use iText7 to add the footer (page count) to delete the original PDF and display the new output.

Huge job, but the only way I found it, since Rotativa and other components that work with wkhtmltopdf.org did not print the CSS correctly.

So my problem is:

How to save the PDF without displaying it? With the example of the site: https://jsreport.net/learn/dotnet-aspnetcore#save-to-file

Itneeds the return View() which makes me unable to display the modified PDF and not the original

.

[MiddlewareFilter(typeof(JsReportPipeline))]
public async Task<IActionResult> InvoiceWithHeader()
{
    HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf);
    HttpContext.JsReportFeature().OnAfterRender((r) => {
        using (var file = System.IO.File.Open("report.pdf", FileMode.Create))
        {
            r.Content.CopyTo(file);
        }
        r.Content.Seek(0, SeekOrigin.Begin);
    });
    return View(InvoiceModel.Example());
}

OnAfterRender does not answer my problem, is there how to do the step as I said? or is there another better solution?

  1. Generate PDF of Action by JsReport
  2. Save PDF from JsReport
  3. Add page count by iText7
  4. Delete original PDF from JsReport
  5. View the pdf modified by iText7 in the view

NOTE: using new jsreport.Local.LocalReporting() works perfectly the problem was when going up to Azure.

Update: I'm tried, but it didn't work

var htmlContent = await JsReportMVCService.RenderViewToStringAsync(HttpContext, RouteData, "/Views/OcorrenciaTalaos/GerarPdf.cshtml", retorno);
(var contentType, var generatedFile) = await GeneratePDFAsync(htmlContent);
using (var fileStream = new FileStream("tempJsReport.pdf", FileMode.Create))
{
    await generatedFile.CopyToAsync(fileStream);
}
        public async Task<(string ContentType, MemoryStream GeneratedFileStream)> GeneratePDFAsync(string htmlContent)
        {
            IJsReportFeature feature = new JsReportFeature(HttpContext);
            feature.Recipe(Recipe.ChromePdf);
            if (!feature.Enabled) return (null, null);
            feature.RenderRequest.Template.Content = htmlContent;

            // var htmlContent = await JsReportMVCService.RenderViewToStringAsync(HttpCSexontext, RouteData, "GerarPdf", retorno);
            var report = await JsReportMVCService.RenderAsync(feature.RenderRequest);
            var contentType = report.Meta.ContentType;
            MemoryStream ms = new MemoryStream();
            report.Content.CopyTo(ms);
            return (contentType, ms);
        }
1 Answers

You can overwrite the final response inside the OnAfterRender this way:

[MiddlewareFilter(typeof(JsReportPipeline))]
public IActionResult InvoiceDownload()
{
    HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf)
        .OnAfterRender((r) =>
        {
            // write current report to file
            using(var fileStream = System.IO.File.Create("c://temp/out.pdf"))
            {                    
                r.Content.CopyTo(fileStream);
            }
            // do modifications
            // ...
            // overwrite response with a new pdf
            r.Content = System.IO.File.OpenRead("c://temp/final.pdf");               
        });

    return View("Invoice", InvoiceModel.Example());
}

However, the page numbers should work and you shouldn't need to do it this complicated way. No matter you are in docker or not. Here is the answer in another question

Related