在.NET平台中操作生成PDF的类库有很多如常见的有iTextSharp、PDFsharp、Aspose.PDF等,我们分享一个用于生成PDF文档的现代开源.NET库:QuestPDF,本文将介绍QuestPDF并使用它快速实现发票PDF文档生成功能。 
QuestPDF介绍 QuestPDF 是一个用于生成 PDF 文档的现代开源 .NET 库。QuestPDF 由简洁易用的 C# Fluent API 提供全面的布局引擎。轻松生成 PDF 报告、发票、导出等。 
QuestPDF它提供了一个布局引擎,在设计时考虑了完整的分页支持。与其他库不同,它不依赖于 HTML 到 PDF 的转换,这在许多情况下是不可靠的。 
相反,它实现了自己的布局引擎,该引擎经过优化,可以满足所有与分页相关的要求。 
QuestPDF License 
分为社区版、专业版、和企业版。 
项目源代码 创建一个控制台应用 创建一个名为 QuestPDFTest 的控制台应用。 
安装QuestPDF Nuget包 搜索: QuestPDF 包进行安装。 
快速实现发票PDF文档生成 创建InvoiceModel namespace  QuestPDFTest   public  class  InvoiceModel   ///  <summary>   ///  发票号码  ///  </summary>   public  int  InvoiceNumber { get ; set ; }  ///  <summary>   ///  发票开具日期  ///  </summary>   public  DateTime IssueDate { get ; set ; }  ///  <summary>   ///  发票到期日期  ///  </summary>   public  DateTime DueDate { get ; set ; }  ///  <summary>   ///  卖方公司名称  ///  </summary>   public  string  SellerCompanyName { get ; set ; }  ///  <summary>   ///  买方公司名称  ///  </summary>   public  string  CustomerCompanyName { get ; set ; }  ///  <summary>   ///  订单消费列表  ///  </summary>   public  List<OrderItem> OrderItems { get ; set ; }  ///  <summary>   ///  备注  ///  </summary>   public  string  Comments { get ; set ; }  public  class  OrderItem   ///  <summary>   ///  消费类型  ///  </summary>   public  string  Name { get ; set ; }  ///  <summary>   ///  消费金额  ///  </summary>   public  decimal  Price { get ; set ; }  ///  <summary>   ///  消费数量  ///  </summary>   public  int  Quantity { get ; set ; }  CreateInvoiceDetails namespace  QuestPDFTest   public  class  CreateInvoiceDetails   private  static  readonly  Random _random = new  Random();  public  enum  InvoiceType  ///  <summary>   ///  获取发票详情数据  ///  </summary>   ///  <returns></returns>   public  static  InvoiceModel GetInvoiceDetails ()return  new  InvoiceModel  1 _000, 10 _000),  14 ),  "追逐时光者" ,  "DotNetGuide技术社区" ,  1 , 20 )  "DotNetGuide技术社区是一个面向.NET开发者的开源技术社区,旨在为开发者们提供全面的C#/.NET/.NET Core相关学习资料、技术分享和咨询、项目推荐、招聘资讯和解决问题的平台。在这个社区中,开发者们可以分享自己的技术文章、项目经验、遇到的疑难技术问题以及解决方案,并且还有机会结识志同道合的开发者。我们致力于构建一个积极向上、和谐友善的.NET技术交流平台,为广大.NET开发者带来更多的价值和成长机会。"   ///  <summary>   ///  订单信息生成  ///  </summary>   ///  <returns></returns>   private  static  OrderItem GenerateRandomOrderItemInfo ()var  types = (InvoiceType[])Enum.GetValues(typeof (InvoiceType));  return  new  OrderItem  decimal )Math.Round(_random.NextDouble() * 100 , 2 ),  1 , 10 )  CreateInvoiceDocument using  QuestPDF.Fluent;  using  QuestPDF.Helpers;  using  QuestPDF.Infrastructure;  namespace  QuestPDFTest   public  class  CreateInvoiceDocument  : IDocument   ///  <summary>   ///  获取Logo的的Image对象  ///  </summary>   public  static  Image LogoImage { get ; } = Image.FromFile("dotnetguide.png" );  public  InvoiceModel Model { get ; }  public  CreateInvoiceDocument (InvoiceModel model )public  DocumentMetadata GetMetadata ()public  void  Compose (IDocumentContainer container )//设置页面的边距   50 );  //字体默认大小18号字体   18 ));  //页眉部分   //内容部分   //页脚部分   " / " );  #region  构建页眉部分   void  BuildHeaderInfo (IContainer container )$"发票编号 #{Model.InvoiceNumber} " ).FontFamily("fangsong" ).FontSize(20 ).SemiBold().FontColor(Colors.Blue.Medium);  "发行日期: " ).FontFamily("fangsong" ).FontSize(13 ).SemiBold();  $"{Model.IssueDate:d} " );  "终止日期: " ).FontFamily("fangsong" ).FontSize(13 ).SemiBold();  $"{Model.DueDate:d} " );  //在当前行的常量项中插入一个图像   130 ).Image(LogoImage);  #endregion    #region  构建内容部分   void  BuildContentInfo (IContainer container )40 ).Column(column =>  20 );  new  AddressComponent("卖方公司名称" , Model.SellerCompanyName));  50 );  new  AddressComponent("客户公司名称" , Model.CustomerCompanyName));  var  totalPrice = Model.OrderItems.Sum(x => x.Price * x.Quantity);  5 ).AlignRight().Text($"总计: {totalPrice} " ).FontFamily("fangsong" ).SemiBold();  if  (!string .IsNullOrWhiteSpace(Model.Comments))  25 ).Element(BuildComments);  ///  <summary>   ///  创建表格  ///  </summary>   ///  <param name="container"> container</param>   void  CreateTable (IContainer container )var  headerStyle = TextStyle.Default.SemiBold();  25 );  3 );  "#" ).FontFamily("fangsong" );  "消费类型" ).Style(headerStyle).FontFamily("fangsong" );  "花费金额" ).Style(headerStyle).FontFamily("fangsong" );  "数量" ).Style(headerStyle).FontFamily("fangsong" );  "总金额" ).Style(headerStyle).FontFamily("fangsong" );  //设置了表头单元格的属性   5 ).PaddingTop(5 ).BorderBottom(1 ).BorderColor(Colors.Black);  foreach  (var  item in  Model.OrderItems)  var  index = Model.OrderItems.IndexOf(item) + 1 ;  $"{index} " ).FontFamily("fangsong" );  "fangsong" );  $"{item.Price} " ).FontFamily("fangsong" );  $"{item.Quantity} " ).FontFamily("fangsong" );  $"{item.Price * item.Quantity} " ).FontFamily("fangsong" );  static  IContainer CellStyle (IContainer container )1 ).BorderColor(Colors.Grey.Lighten2).PaddingVertical(5 );  #endregion    #region  构建页脚部分   void  BuildComments (IContainer container )10 ).Column(column =>  5 );  "DotNetGuide技术社区介绍" ).FontSize(14 ).FontFamily("fangsong" ).SemiBold();  "fangsong" );  #endregion    public  class  AddressComponent  : IComponent   private  string  Title { get ; }  private  string  CompanyName { get ; }  public  AddressComponent (string  title, string  companyNamepublic  void  Compose (IContainer container )2 );  "fangsong" ).SemiBold();  5 ).LineHorizontal(1 );  "fangsong" );  Program using  QuestPDF;  using  QuestPDF.Fluent;  using  QuestPDF.Infrastructure;  namespace  QuestPDFTest   internal  class  Program   static  void  Main (string [] args// 1、请确保您有资格使用社区许可证,不设置的话会报异常。   // 2、禁用QuestPDF库中文本字符可用性的检查   false ;  // 3、PDF Document 创建   var  invoiceSourceData = CreateInvoiceDetails.GetInvoiceDetails();  var  document = new  CreateInvoiceDocument(invoiceSourceData);  // 4、生成 PDF 文件并在默认的查看器中显示   完整示例源代码 https://github.com/YSGStudyHards/QuestPDFTest 
示例运行效果图 注意问题 中文报异常 QuestPDF.Drawing.Exceptions.DocumentDrawingException:“Could not find an appropriate font fallback for  glyph: U-53 D1 '发' . Font families available on  current environment that contain this  glyph: Microsoft JhengHei, Microsoft JhengHei UI, Microsoft YaHei, Microsoft YaHei UI, SimSun, NSimSun, DengXian, FangSong, KaiTi, SimHei, FZCuHeiSongS-B-GB. Possible solutions: 1 ) Use one of the listed fonts as  the primary font in  your document. 2 ) Configure the fallback TextStyle using  the 'TextStyle.Fallback'  method with one of the listed fonts. You can disable this  check by  setting the 'Settings.CheckIfAllTextGlyphsAreAvailable'  option to 'false' . However, this  may result with text glyphs being incorrectly rendered without any warning.”   加上这段代码 
// 2、禁用QuestPDF库中文本字符可用性的检查   false ;  原因: 默认情况下,使用 QuestPDF 生成 PDF 文档时,它会检查所使用的字体是否支持文本中的所有字符,并在发现不能显示的字符时输出一条警告消息。这个选项可以确保文本中的所有字符都能正确地显示在生成的 PDF 文件中。
中文乱码问题 解决方案 
假如Text("")中为汉字一定要在后面加上FontFamily("fangsong")[仿宋字体]或FontFamily("simhei")[黑体字体],否则中文无法正常显示。 
项目源码地址 GitHub地址:https://github.com/QuestPDF/QuestPDF  
文档地址:https://www.questpdf.com/api-reference/