Creating PDF on ASP.NET Core
Creating PDF files on ASP.NET Core has been issue for awhile. I needed some proof-of-concept solution to prove it’s possible to generate PDF files on ASP.NET Core easily without writing a lot of code or going through complex configuration. I solved the problem and here is my solution.
The best and most polished solution I found was Rotativa.AspNetCore. It takes some additional steps after installing NuGet package but it’s nothing complex. And what’s best – it is cross-platform package that works also on Linux and Apple machines.
Making Rotativa.AspNetCore work on Windows
You can find these files from wwwroot/Rotiva folder of Rotativa.AspNetCore demo application repository at GitHub here. Just download these files and put them to Rotativa folder under project root like shown on the image on rights.
Before we can start with PFD we have to tell in configuration where those additional files are located.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
RotativaConfiguration.Setup(env, "..\\Rotativa\\");
}
On preparation side this is all when going with Windows. On Linux and Apple you may need some additional libraries to be available.
Invoice models
To make my proof-of-concept code more realistic I decided to go with simple invoice. Here are models for Invoice and InvoiceLine.
public class Invoice
{
public string InvoiceNo { get; set; }
public string CustomerName { get; set; }
public string CustomerBillingAddress { get; set; }
public DateTime InvoiceDate { get; set; }
public DateTime DueDate { get; set; }
public IList<InvoiceLine> Lines { get; set; }
public Invoice()
{
Lines = new List<InvoiceLine>();
}
public decimal Total
{
get
{
return Lines.Sum(l => l.Total);
}
}
public decimal Vat
{
get
{
return Lines.Sum(l => l.Vat);
}
}
public static Invoice GetOne()
{
var invoice = new Invoice();
invoice.CustomerBillingAddress = "Wellington str. 2-311, 10113, NY, USA";
invoice.CustomerName = "Imaginary Corp.";
invoice.DueDate = DateTime.Now.AddDays(30);
invoice.InvoiceDate = DateTime.Now.Date;
invoice.InvoiceNo = "B383810312-2213";
var line = new InvoiceLine();
line.Amount = 12;
line.LineTitle = "Fancy work desks";
line.UnitPrice = 800;
line.VatPercent = 20;
invoice.Lines.Add(line);
line = new InvoiceLine();
line.Amount = 5;
line.LineTitle = "Espresso machines";
line.UnitPrice = 200;
line.VatPercent = 20;
invoice.Lines.Add(line);
line = new InvoiceLine();
line.Amount = 30;
line.LineTitle = "Meeting room whiteboards";
line.UnitPrice = 50;
line.VatPercent = 20;
invoice.Lines.Add(line);
return invoice;
}
} public class InvoiceLine
{
public string LineTitle { get; set; }
public decimal UnitPrice { get; set; }
public int Amount { get; set; }
public int VatPercent { get; set; }
public decimal Net
{
get
{
return UnitPrice * Amount;
}
}
public decimal Total
{
get
{
return Net * (1 + VatPercent / 100M);
}
}
public decimal Vat
{
get
{
return Net * (VatPercent / 100M);
}
}
}
Notice that Invoice class has static method GetOne() that created demo invoice for us.
Building invoice view
We have invoice and now we need view to show it. I named view as Invoice.cshtml. It doesn’t use layout page as we don’t need any frame UI shown around the view.
@model Invoice
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Invoice @Model.InvoiceNo</title>
<link rel="stylesheet" href="@Url.Content("~/css/invoice-report.css")" />
</head>
<body>
<div class="invoice-title">
Invoice @Model.InvoiceNo
</div>
<div class="invoice-head clearfix">
<div class="invoice-to">
<strong>@Model.CustomerName</strong><br />
@Model.CustomerBillingAddress
</div>
<div class="invoice-details">
Invoice no: @Model.InvoiceNo<br />
Date: @Model.InvoiceDate.ToShortDateString()<br />
Due date: @Model.DueDate.ToShortDateString()
</div>
</div>
<table>
<tr>
<th>Item</th>
<th>Unit price</th>
<th>Amount</th>
<th>Net</th>
<th>VAT (%)</th>
<th>Total</th>
</tr>
@foreach(var line in Model.Lines)
{
<tr>
<td>@line.LineTitle</td>
<td class="numeric-cell">@line.UnitPrice.ToString("0.00") EUR</td>
<td class="numeric-cell">@line.Amount</td>
<td class="numeric-cell">@line.Net.ToString("0.00") EUR</td>
<td class="numeric-cell">@line.VatPercent%</td>
<td class="numeric-cell">@line.Total.ToString("0.00") EUR</td>
</tr>
}
<tr>
<td colspan="4"></td>
<td><strong>Total:</strong></td>
<td><strong>@Model.Total.ToString("0.00") EUR</strong></td>
</tr>
</table>
</body>
</html>
This view with styles forms nice invoice we can also show in browser to print it out. Here are styles for view.
body {
margin: 0px;
font-family: 'Segoe UI', Arial;
}
.invoice-head {
clear:both;
display:block;
padding: 10px;
margin-bottom: 40px;
}
.invoice-title {
background-color: navy;
color: white;
font-size: 20px;
padding: 10px;
width: 100%;
}
.invoice-to {
float:left;
}
.invoice-details {
float:right;
}
table {
clear: both;
border: 1px solid darkgray;
border-collapse: collapse;
margin: auto;
}
th {
background-color: navy;
color: white;
}
td, th {
border: 1px solid darkgray;
padding: 5px;
}
.numeric-cell {
text-align:right;
}
.clearfix::after {
content: "";
clear: both;
display: table;
}
Here is InvoiceHtml() action I added to Home controller.
public IActionResult InvoiceHtml()
{
return View("Invoice", Invoice.GetOne());
}
When running web application and going to /InvoiceHtml address we will see the invoice like shown below.
Creating PDF invoice
Let’s add now another action to Home controller and name it as InvoicePDF(). This action uses the same view we built above but it turns to PDF-file.
public IActionResult InvoicePdf()
{
return new ViewAsPdf("Invoice", Invoice.GetOne());
}
One thing to notice – instead of another hell of code to just get the PDF and get it to browser we have single line of code that takes care of everything. Here is our invoice as PDF-file.
Two flies with one hit – invoice in browser ready for printing and invoice as PDF-file ready for download.
Wrapping up
There are not many cross-platform options to generate PDF-files on ASP.NET Core but ??? is the best one I met this far. Although it needs some small steps to do besides adding a NuGet package to solution it is still simple enough to go with it. I like the idea that it is easy to generate PDF-file based on view and return it as an action result without writing any additional code.
Pingback:Dew Drop – May 8, 2018 (#2720) | Morning Dew
Have you tested this Invoice example with a multi-page invoice? If you had too many invoice lines to fit on a single page, how could you create a multi-page invoice with header/footer and page numbers on each page?
Pingback:Szumma #109 – 2018 19. hét + Microsoft Build 2018 – ./d/fuel
Jake, there are some options to set margings etc. I will dig around there and write new blog post if I find something useful for more complex features.
I would suggest to try ZetPDF.com that works so well in generating pdf files into .net
Derek, is ZetPDF commercial product or not? I cannot read it out from their homepage.
Nice article! It’s really helpful!
As a professional content writer, who constantly works with PDF files, I would also suggest https://zetpdf.com/. It’s really convenient and easy to use.
Word of warning – that ZetPDF.com site is an obvious scam
thanks heaps Gunnar! Saved me a heap of time.
ZetPDF is a C ASP NET VB NET PDF API to create PDF documents from scratch using API or XML PDF library for Windows Forms, WPF and Silverlight as well
https://zetpdf.com
I did this step by step, but not generate razor codes to PDF and i don’t know why
thank you
Please check output window in Visual Studio when requesting PDF generating action in browser. Do you see any warnings there or errors?
In Chrome browser: I find ‘Print to PDF’ option. Why should I, now, use this extension?
You should use it if you need to let users download PDF documents generated online. Not all your site users have Chrome or print-to-PDF printer driver in their machine. Some of your users maybe don’t even open the PDF file they downloaded. Let’s say office assistant downloads PDF invoice and sends it to accounting or registers it in document management system.
‘IHostingEnvironment’ is obsolete in Core 3.0 so, how can i user in my Core 3.0 project.
This is what is said on project page:
“Basic configuration done in Startup.cs:
RotativaConfiguration.Setup(env);
or, if using Asp.net Core 3.0:
RotativaConfiguration.Setup(“”, “path/relative/to/root”);”
Line is not breaking in table td
can it work if the .net core deploy on linux server?
Yes, because the same wkhtmltoimage and wkhtmltopdf libraries are also available for Linux.
Oh, okay. I see. Thanks
Excellent thanks for this
Do you have an example of filling the data from a sql database instead of just using hard coded values?
i have a Print PDF button on my page, when the user clicks it, the page is moved to the PDF preview, is there anyway to force this to a new tab, when the user clicks on the button?
thx
I have build a web application with asp.net on a windows machine and deploied to Ubuntu.
I copied the msc*120.dll’s from Windows to the wwwroot/rotativa directory, but it’s still not working.
Any idea, what I did wrong?
Why do you need MS dll-s on Ubuntu? There should be separate wk* files for Linux distros.
YES YES YES
Great Work
Thank u Very much
After searching 5 days in GOOGLE FINALLY Get the Output.
Zetpdf is the great lieabrt to creat PDF on asp.net
Do you have a spam problem on this website; I also am
a blogger, and I was wanting to know your situation;
we have created some nice procedures and we are looking to swap methods with other folks, be sure to shoot me an email if interested.
Everything is very open with a clear clarification of the issues.
It was really informative. Your site is very useful.
Many thanks for sharing!
Hello dear friend! This article taught me a lot. If you want to rank better, buy sidebar backlinks from
virgool.io. You can DM me on Telegram @myd_80 or join my SEO group @seoprem.
Remember, the magic of internal seo is for mehran yousefi, and the
best telegram seo group link is: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We’ve
also got guest posts for sale.
Greetings readers! This content totally impressed me. I suggest you invest in sidebar backlinks from virgool.io.
If you want to rank better, DM me on Telegram @myd_80 or visit
my SEO group @seoprem. We have guest posts for sale.
Also, the best telegram seo group and the magic of internal seo is for mehran yousefi at https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx.
Hello everyone! I really liked this article. You can definitely enhance SEO
results by buying sidebar backlinks from virgool.io. If you want to rank better, contact me on Telegram @myd_80 or check out my SEO group @seoprem.
Also, the best SEO backlinks services are from mehran yousefi.
Don’t forget, the best telegram seo group
is in this link: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We additionally offer guest
posts for sale.
Hi readers! I really liked this post. One can surely boost search visibility by geting hold of sidebar backlinks from virgool.io.
If you want to rank better, text me on Telegram @myd_80 or visit my SEO group @seoprem.
Also, the best SEO backlinks services are from mehran yousefi.
Don’t forget, the best telegram seo group is in this link: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We also have guest
posts for sale.
Hi dear friend! This article was so well-done. I suggest you grab sidebar backlinks from virgool.io.
If you want to rank better, DM me on Telegram
@myd_80 or come join my SEO group @seoprem. Also,
the best telegram seo group can be found with mehran yousefi.
The link is: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We have guest posts for sale too.
Hello all! This content was so thorough. I suggest you grab sidebar backlinks
from virgool.io. If you want to rank better, send a message
me on Telegram @myd_80 or visit my SEO group @seoprem.
Also, the best telegram seo group can be found with mehran yousefi.
The link is: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We have
guest posts for sale too.
Hey everyone! This platform is truly insightful.
I suggest you get sidebar backlinks from virgool.io. If you
want to rank better, contact me on Telegram @myd_80 or hop into my SEO group
@seoprem. The best telegram seo group is there, and the magic of internal seo is for mehran yousefi.
We also have the best SEO backlinks services.
Excellent weblog right here! Also your web site lots up very fast!
What host are you the usage of? Can I get your associate link on your host?
I wish my website loaded up as fast as yours lol
Hey everyone! This site is definitely insightful.
I suggest you get sidebar backlinks from virgool.io. If you want to rank better,
simply reach me on Telegram @myd_80 or check out my SEO group @seoprem.
The best telegram seo group is there, and the magic of internal seo is for mehran yousefi.
We also have guest posts for sale.
Hey all! This article was so in-depth. I suggest
you buy sidebar backlinks from virgool.io. If you want to rank better, DM me on Telegram @myd_80 or check my SEO group
@seoprem. Also, the best telegram seo group can be found with mehran yousefi.
The link is: https://virgool.io/@yousefimehran2001/گروه-تلگرام-سئو-j7scgevxnkxx. We have guest
posts for sale too.
درود هواداران، این پست بهم بینش داد.
یه پلتفرم خبری بینقص دارم که خبرهای بهروز و
موثق داره. میتونی یه سر بزن برای خبرهای
بهروز.
درود مردم، عجيب اين خبر واقعاً منو
تحت تأثير قرار داد. با يه سايت خبري بينظير آشنا شدم كه
اخبار قابل اعتماد و جديدي داره.
ميتوني حتماً ببين تا اطلاعات موثق رو ببيني.
سلام همه عزيزان، خيلي از مطالعه اين لذت بردم پست
عاشقش شدم. با يه سايت خبري عالي آشنا شدم كه خبرهاش
معتبر و بهروزه. اگه علاقهمند به خبرهاي معتبر هستي، زود سر بزن.
درود جامعه، این نوشته فوقالعاده برام جالب بود.
با یه سایت خبری بینظیر
آشنا شدم که اخبار قابل اعتماد و جذاب داره.
میتونی حتماً یه نگاه بنداز برای خبرهای تازه.
هيجانانگيز خوانندگان، عجيباين مطلب بينهايت بهم انگيزهداد.
يه وبسايت خبري جذاب پيدا كردم كه خبرهاي تازه و موثقي
داره. ميتوني يه نگاه بنداز تا
اخبار بهروز رو ببيني.
My sіte; اخبار روز (Staci)
روز بخير همه، همهی اين خبر عجيب منو شيفته كرد.
با يه منبع خبري عالي آشنا شدم كه خبرهاي
هيجانانگيز و دقيقي داره. ميتوني دنبال كن
تا اخبار دقيق رو ببيني.
my homepage: اخبار مهم (Tammie)
I was curious if you ever considered changing the
page layout of your blog? Its very well written; I love what youve got to
say. But maybe you could a little more in the way of content so people could connect with it better.
Youve got an awful lot of text for only having one
or two images. Maybe you could space it out better?
If some one wishes expert view on the topic of blogging afterward i advise him/her to go
to see this webpage, Keep up the good job.
I have read so many articles regarding the blogger lovers
except this article is genuinely a good article,
keep it up.
Hi Dear, are you truly visiting this web page on a regular basis, if so afterward
you will absolutely take good know-how.
I always used to study article in news papers but
now as I am a user of internet therefore from now I am using net for articles, thanks
to web.