【问题标题】:Asp.Net MVC how to get view to generate PDFAsp.Net MVC 如何获取视图以生成 PDF
【发布时间】:2010-10-21 05:38:21
【问题描述】:

我想在控制器上调用一个动作。让控制器从模型中获取数据。然后视图运行并生成 PDF。我发现的唯一例子是 Lou http://whereslou.com/2009/04/12/returning-pdfs-from-an-aspnet-mvc-action 的一篇文章。他的代码非常优雅。该视图使用 ITextSharp 生成 PDF。唯一的缺点是他的示例使用了 Spark View Engine。有没有办法用标准的微软视图引擎做类似的事情?

【问题讨论】:

  • 使用 Spark 视图引擎有缺点吗?我受伤了。 :)
  • 我一直在努力解决这个问题。带有 iText 的 Spark 易于使用,但 PDF 格式有限。我很想看到您使用模板 PDF 文件、更改内容然后写入流的示例。
  • 看看这个,RazorPDF:nyveldt.com/blog/post/Introducing-RazorPDF
  • 为了后代,我们现在使用Rotativa,它包装了wkhtmltopdf

标签: asp.net-mvc pdf


【解决方案1】:

我使用 iTextSharp 在 MVC 中生成动态 PDF。您需要做的就是将您的 PDF 放入一个 Stream 对象,然后您的 ActionResult 返回一个 FileStreamResult。我还设置了 content-disposition 以便用户可以下载它。

公共 FileStreamResult PDFGenerator() { 流文件流 = GeneratePDF(); HttpContext.Response.AddHeader("内容配置", “附件;文件名=form.pdf”); return new FileStreamResult(fileStream, "application/pdf"); }

我还有一些代码可以让我获取模板 PDF、向其中写入文本和图像等(如果你想这样做的话)。

  • 注意:必须将 Stream 位置设置为 0。
私有流 GeneratePDF() { //创建您的pdf并将其放入流中...下面的pdf变量 //来自我用来将内容写入 PDF 文件的类 内存流毫秒 = 新的内存流(); byte[] byteInfo = pdf.Output(); ms.Write(byteInfo, 0, byteInfo.Length); ms.位置 = 0; 返回毫秒; }

【讨论】:

  • 我很想看看示例中的“pdf 类”是什么样子的,或者得到一些关于如何实现它的提示?
  • 我唯一要补充的是,不能从部分回发 (ajax) 调用此操作,而是使用 Html.ActionLink 等。
  • 带有示例代码的代码项目文章:codeproject.com/Articles/66948/…
  • 由于issue with duplicate Content-Disposition,添加 Content-Disposition 标头在 FireFox 中不起作用。正确的解决方案是设置 FireStreamResult 对象的 FileDownloadName 属性。
  • @David,在我的项目中,我有基于角色的操作授权,但是当我使用 pdf 时,它只打印登录屏幕
【解决方案2】:

我们对这个问题的最终答案是使用Rotativa。

它像其他一些解决方案一样封装了 WKhtmltopdf.exe,但它是迄今为止我发现的最容易使用的

我对所有其他也很好地解决了问题的答案都投了赞成票,但这就是我们用来解决上述问题中提出的问题的方法。它与其他答案不同。

这是Rotativa Tutorial。

安装后,这就是你所需要的

public ActionResult PrintInvoice(int invoiceId)
{
  return new ActionAsPdf(
                 "Invoice", 
                 new { invoiceId= invoiceId }) 
                 { FileName = "Invoice.pdf" };
}

非常非常简单。

【讨论】:

  • 为什么投反对票,我很困惑。这就是我们现在解决问题的方式,所以我更新了问题以使其保持最新状态。我不明白。如果我不明白为什么我投了反对票,我该如何做得更好?
  • 再次投反对票,没有评论......这是我们用来解决问题的答案。我付出了额外的努力,用最新的答案回来更新问题。除非您只是不喜欢 rotativa,否则我很困惑如何评价否决票。
  • Brown 美丽的答案,绝对没有代码,这就是我们在 21 世纪所需要的。 +1 为 cmets 和 answer..thanks heaps
  • 它根本行不通。当我使用 ViewAsPdf 时,它给了我一个错误:“目录名称无效”
  • 问自己一个问题,在那段代码中,什么隐含了目录名称?文件名...所以请确保您正在找到正确的 .pdf 路径。
【解决方案3】:

在 html 中创建布局,然后打印成 pdf 是最快的方法。

HTML转pdf由phantomjs、wkhtmltopdf或jsreport提供

jsreport 提供与 asp.net mvc 视图的直接集成, 您可以在其中使用属性标记控制器操作,它会为您打印 pdf 而不是 html。

更多关于blog post

免责声明:我是jsreport的作者

【讨论】:

  • 如果你使用 MVC,Rotativa 是一个非常好的 wkhtmltopdf 包装器...超级好用,我们现在已经转换为它来解决这个问题...图像有问题,但是有一个解决方法
  • 是的,Rorativa 是一个不错的包装。 jsreport 是一个为您处理图像或保留报告历史记录的报告服务器。
【解决方案4】:

这是一个古老的问题,但仍然具有相关性,我想我只是分享一下我实施的效果很好的问题。

  1. 安装 NuGet 包 TuesPechkin - 基于 WkHtmlToPdf 的 Pechkin 库中的一个分支,它使用 Webkit 引擎将 HTML 页面转换为 PDF。

  2. 编写一个小助手来读取视图并将其转换为 HTML 字符串(mvcContext 是 this.HttpContext)。替换当然是可选的!:

    public static string RenderViewToString(HttpContextBase mvcContext, string area, string controllerName, string viewName, object model)
    {
        var context = System.Web.HttpContext.Current;
        var contextBase = mvcContext;
        var routeData = new RouteData();
        if (area == null) area = "";
    
        routeData.DataTokens.Add("area", area);
    
        routeData.Values.Add("controller", controllerName);
    
        var controllerContext = new ControllerContext(contextBase,
                                                routeData,
                                                new EmptyController());
    
        var razorViewEngine = new RazorViewEngine();
        var razorViewResult = razorViewEngine.FindView(controllerContext,
                                                    viewName,
                                                    "",
                                                false);
    
        var writer = new StringWriter();
        var viewContext = new ViewContext(controllerContext,
                                    razorViewResult.View,
                                    new ViewDataDictionary(model),
                                    new TempDataDictionary(),
                                    writer);
        razorViewResult.View.Render(viewContext, writer);
    
        string hostAddress = context.Request.Url.Scheme + "://" + context.Request.Url.Authority;
    
        return writer.ToString()
                     .Replace("src=\"/", "src=\"" + hostAddress + "/")
                     .Replace("<link href=\"/", "<link href=\"" + hostAddress + "/");                         
    }
    
    class EmptyController : ControllerBase
    {
        protected override void ExecuteCore() { }
    }
    

以上的辛苦都来自这里:http://wouterdekort.blogspot.co.uk/2012/10/rendering-aspnet-mvc-view-to-string-in.html?showComment=1414603363455#c7863520150405064571

  1. 创建一个 MVC Action 来生成文档

    public ActionResult DownloadPDF(long CentreID)
    {
        var model = GetModel()
    
        IPechkin converter = Factory.Create();
        byte[] result = converter.Convert(Helpers.PDF.RenderViewToString(this.HttpContext, "area", "controller", "action", model);
        MemoryStream outputStream = new MemoryStream();
        outputStream.Write(result, 0, result.Length);
        outputStream.Position = 0;
    
        return File(outputStream, "application/pdf", "filename.pdf");
    }
    

【讨论】:

  • 对于那些遵循本教程并在 IPechkin 和 Factory 上出现错误的人来说,这是因为它已经被弃用了。请在 github.com/tuespetre/TuesPechkin 阅读如何在 repo 本身上安装和实施。
  • 另外,在你从nuget下载TuesPechkin后,别忘了下载TuesPechkin.Wkhtmltox.Win32或TuesPechkin.Wkhtmltox.Win64,因为下载时不包含。
  • 这应该是最佳答案之一。正是我想要的,它是开源的。
【解决方案5】:

我也遇到过这个http://www.codeproject.com/Articles/260470/PDF-reporting-using-ASP-NET-MVC3。它简单快捷,非常适合 MVC。

然而,到目前为止唯一的缺点是它不太灵活,你想要一个像样的布局,例如,你对表格没有太多控制,通过 html 来控制单元格边框。它有点支持强制新页面,但您必须对 iTextsharp 应用补丁。

【讨论】:

    【解决方案6】:

    我只是使用 wkhtmltopdf,在 html 中创建布局,然后将其转换为 pdf。

    简单,可定制,真棒:)

    【讨论】:

    • 我假设你的意思是 wkhtmltopdf
    【解决方案7】:

    回复很晚,但我发现以下 URL 帮助我快速获得结果:

    (确保您通过使用 Nuget 包来引用 iTextSharp DLL)

    https://www.aspsnippets.com/Articles/Export-Grid-Html-Table-data-from-database-to-PDF-file-using-iTextSharp-in-ASPNet-MVC.aspx

    编辑 这是我用来使表格看起来有点不同的代码(这也是风景:

    public string GetCssForPdf()
            {
                string css = "";
    
                css = "th, td" +
                       "{" +
                           "font-family:Arial; font-size:10px" +
                        "}";
    
                return css;
            }
    
    [HttpPost]
            [ValidateInput(false)]
            public FileResult Export(string GridHtml)
            {
                string webgridstyle = GetCssForPdf();
    
                string exportData = String.Format("<html><body>{0}{1}</body></html>", "<style>" + webgridstyle + "</style>", GridHtml);
                var bytes = System.Text.Encoding.UTF8.GetBytes(exportData);
    
                using (var input = new MemoryStream(bytes))
                {
                    var output = new MemoryStream();
                    var document = new iTextSharp.text.Document(PageSize.A4, 50, 50, 50, 50);
                    var writer = PdfWriter.GetInstance(document, output);
    
                    document.SetPageSize(iTextSharp.text.PageSize.A4.Rotate());
                    Font headerFont = FontFactory.GetFont("Verdana", 10);
                    Font rowfont = FontFactory.GetFont("Verdana", 10);
    
                    writer.CloseStream = false;
                    document.Open();
    
                    var xmlWorker = iTextSharp.tool.xml.XMLWorkerHelper.GetInstance();
                    xmlWorker.ParseXHtml(writer, document, input, System.Text.Encoding.UTF8);
                    document.Close();
                    output.Position = 0;
    
                    return File(output, "application/pdf", "Pipeline_Report.pdf");
    
                    //return new FileStreamResult(output, "application/pdf");
                }
            }
    

    希望这对其他人也有帮助。

    【讨论】:

      【解决方案8】:

      在asp.net mvc中使用rotativa包的小例子

      我们将创建一个函数来填充数据。我们将插入 7 天(2018 年 2 月 1 日 - 2018 年 2 月 7 日)的数据,显示特定日期的第一拳和最后一拳并附上备注。

      public ReportViewModel PopulateData()
              {
                  var attendances = new List<Attendance>
                  {
                      new Attendance{ClassName = "present",Day = new DateTime(2018, 02, 01).ToString("ddd"),Date = new DateTime(2018, 02, 01).ToString("d"),FirstPunch = "09:01:00",LastPunch = "06:00:01",Remarks = ""},
                      new Attendance{ClassName = "absent",Day = new DateTime(2018, 02, 02).ToString("ddd"),Date = new DateTime(2018, 02, 02).ToString("d"),FirstPunch = "",LastPunch = "",Remarks = "Absent"},
                      new Attendance{ClassName = "holiday",Day = new DateTime(2018, 02, 03).ToString("ddd"),Date = new DateTime(2018, 02, 03).ToString("d"),FirstPunch = "",LastPunch = "",Remarks = "Democracy Day"},
                      new Attendance{ClassName = "present",Day = new DateTime(2018, 02, 04).ToString("ddd"),Date = new DateTime(2018, 02, 04).ToString("d"),FirstPunch = "09:05:00",LastPunch = "06:30:01",Remarks = ""},
                      new Attendance{ClassName = "present",Day = new DateTime(2018, 02, 05).ToString("ddd"),Date = new DateTime(2018, 02, 05).ToString("d"),FirstPunch = "09:01:00",LastPunch = "06:00:01",Remarks = ""},
                      new Attendance{ClassName = "leave",Day = new DateTime(2018, 02, 06).ToString("ddd"),Date = new DateTime(2018, 02, 06).ToString("d"),FirstPunch = "",LastPunch = "",Remarks = "Sick Leave"},
                      new Attendance{ClassName = "present",Day = new DateTime(2018, 02, 07).ToString("ddd"),Date = new DateTime(2018, 02, 07).ToString("d"),FirstPunch = "08:35:00",LastPunch = "06:15:01",Remarks = ""}
                  };
      
      
                  return new ReportViewModel
                  {
                      UserInformation = new UserInformation
                      {
                          FullName = "Ritesh Man Chitrakar",
                          Department = "Information Science"
                      },
                      StartDate = new DateTime(2018, 02, 01),
                      EndDate = new DateTime(2018, 02, 07),
                      AttendanceData = attendances
                  };
              }
      

      然后我们将创建一个下载 PDF 的函数。要下载 pdf,我们需要创建 2 个函数。 1.下载pdf 2.查看pdf

      public ActionResult DownloadPdf()
              {
                  var filename = "attendance.pdf";
      
                  /*get the current login cookie*/
                  var cookies = Request.Cookies.AllKeys.ToDictionary(k => k, k => Request.Cookies[k]?.Value);
      
                  return new ActionAsPdf("PdfView", new
                  {
                      startDate = Convert.ToDateTime(Request["StartDate"]),
                      endDate = Convert.ToDateTime(Request["EndDate"])
                  })
                  {
                      FileName = filename,
                      /*pass the retrieved cookie inside the cookie option*/
                      RotativaOptions = {Cookies = cookies}
                  };
              }
      
      public ActionResult PdfView()
              {
                  var reportAttendanceData = PopulateData();
      
                  return View(reportAttendanceData);
              }
      

      您可以在此链接上查看详细说明。 访问here。

      柯特索伊:thelearninguy.com

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-22
        • 2015-11-22
        • 1970-01-01
        • 1970-01-01
        • 2011-06-17
        • 2018-08-08
        • 2010-12-18
        • 2011-11-29
        相关资源
        最近更新 更多