In this blog you will see how easy it is to build a report in an ASP.Net MVC application using a free IText PDF libraries.  By the way,  this project is still ASP.Net Webforms MVC 2, if you are already using Razor don’t just cut and paste the sample code, just get the jest and re-write it to suite to your project.

The first step is to add the libraries in your Visual Studio 2013 project by simply using the Manage NuGet Packages.

Once the libraries are installed, just create a controller.  In my example, I named my controller SysReport because I want it to be a generic report controller for all my reporting needs.  The code contains one GET method and a bunch of private methods that returns a PDF MemoryStream created by ITextPDF.

using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http; 

namespace wfmis.Controllers
{
    public class SysReportController : ApiController
    {
        public HttpResponseMessage Get()
        {
            NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
            string Report = nvc["Report"].ToString();
            Int64 Id = Convert.ToInt64(nvc["Id"]);
            var response = new HttpResponseMessage(HttpStatusCode.OK); 

            switch (Report)
            {
                case "PurchaseOrder":
                    response.Content = new StreamContent(this.PurchaseOrder(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

                    break;
                case "PurchaseInvoice":
                    response.Content = new StreamContent(this.PurchaseInvoice(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "Disbursement":
                    response.Content = new StreamContent(this.Disbursement(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "SalesOrder":
                    response.Content = new StreamContent(this.SalesOrder(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "SalesInvoice":
                    response.Content = new StreamContent(this.SalesInvoice(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "Collection":
                    response.Content = new StreamContent(this.Collection(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "JournalVoucher":
                    response.Content = new StreamContent(this.JournalVoucher(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "StockIn":
                    response.Content = new StreamContent(this.StockIn(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "StockOut":
                    response.Content = new StreamContent(this.StockOut(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
                case "StockTransfer":
                    response.Content = new StreamContent(this.StockTransfer(Id));
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                    break;
            } 

            return response;
        }
    }
}

The second part of the controller is the method that creates the report itself.  Noticed that in the above code I highlighted two lines, the first line, calls the method that creates the byte stream while the second line informs the controller what is the content type, those are the methods.  I cannot paste the entire code that contains all the methods because it will take a lot of typing space, what I can paste is just one sample method, PurchaseInvoice.

private MemoryStream PurchaseInvoice(Int64 Id)
{
    var doc = new Document(PageSize.LETTER, 50, 50, 25, 25);
    var stream = new MemoryStream(); 

    try
    {
        BaseFont BaseFontTimesRoman = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
        Font TitleFont = new Font(BaseFontTimesRoman, 18, Font.BOLD);
        Font SubTitleFont = new Font(BaseFontTimesRoman, 14, Font.BOLD);
        Font TableHeaderFont = new Font(BaseFontTimesRoman, 10, Font.BOLD);
        Font BodyFont = new Font(BaseFontTimesRoman, 10, Font.NORMAL);
        Font EndingMessageFont = new Font(BaseFontTimesRoman, 10, Font.ITALIC); 

        PdfWriter writer = PdfWriter.GetInstance(doc, stream); 

        writer.PageEvent = new PDFHeaderFooter("Purchase Invoice"); 

        var PurchaseInvoices = from d in db.TrnPurchaseInvoices where d.Id == Id select d; 

        doc.Open(); 

        var HeaderTable = new PdfPTable(2);
        HeaderTable.HorizontalAlignment = 0;
        HeaderTable.SpacingBefore = 20;
        HeaderTable.SpacingAfter = 10;
        HeaderTable.DefaultCell.Border = 0;
        HeaderTable.SetWidths(new int[] { 2, 6 }); 

        HeaderTable.AddCell(new Phrase("PI Number:", TableHeaderFont));
        HeaderTable.AddCell(new Phrase(PurchaseInvoices.First().PINumber, BodyFont));
        HeaderTable.AddCell(new Phrase("PI Date:", TableHeaderFont));
        HeaderTable.AddCell(new Phrase(PurchaseInvoices.First().PIDate.ToShortDateString(), BodyFont));
        HeaderTable.AddCell(new Phrase("Supplier:", TableHeaderFont));
        HeaderTable.AddCell(new Phrase(PurchaseInvoices.First().MstArticle.Article, BodyFont));
        HeaderTable.AddCell(new Phrase("Term:", TableHeaderFont));
        HeaderTable.AddCell(new Phrase(PurchaseInvoices.First().MstTerm.Term, BodyFont));
        HeaderTable.AddCell(new Phrase("Document Reference:", TableHeaderFont));
        HeaderTable.AddCell(new Phrase(PurchaseInvoices.First().DocumentReference, BodyFont)); 

        doc.Add(HeaderTable); 

        var DetailTable = new PdfPTable(7);
        DetailTable.HorizontalAlignment = 0;
        DetailTable.SpacingAfter = 10;
        DetailTable.DefaultCell.Border = 0;
        DetailTable.SetWidths(new int[] { 2, 2, 6, 3, 3, 3, 3 });
        DetailTable.WidthPercentage = 100;
        DetailTable.DefaultCell.Border = Rectangle.BOX; 

        DetailTable.AddCell(CreateCenterAlignedCell("Qty", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Unit", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Item", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Particulars", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Cost", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Tax", TableHeaderFont, 1));
        DetailTable.AddCell(CreateCenterAlignedCell("Amount", TableHeaderFont, 1)); 

        decimal TotalAmount = 0;
        if (PurchaseInvoices.First().TrnPurchaseInvoiceLines.Any())
        {
            foreach (var Line in PurchaseInvoices.First().TrnPurchaseInvoiceLines)
            {
                DetailTable.AddCell(CreateRightAlignedCell(Line.Quantity.ToString("#,##0.#0"), BodyFont,1));
                DetailTable.AddCell(new Phrase(Line.MstUnit.Unit, BodyFont));
                DetailTable.AddCell(new Phrase(Line.MstArticle.Article, BodyFont));
                DetailTable.AddCell(new Phrase(Line.Particulars, BodyFont));
                DetailTable.AddCell(CreateRightAlignedCell(Line.Cost.ToString("#,##0.#0"), BodyFont,1));
                DetailTable.AddCell(new Phrase(Line.MstTax.TaxCode, BodyFont));
                DetailTable.AddCell(CreateRightAlignedCell(Line.Amount.ToString("#,##0.#0"), BodyFont,1)); 

                TotalAmount = TotalAmount + Line.Amount;
            }
        } 

        DetailTable.AddCell(CreateCenterAlignedCell("TOTAL", TableHeaderFont, 6));
        DetailTable.AddCell(CreateRightAlignedCell(TotalAmount.ToString("#,##0.#0"), TableHeaderFont, 1)); 

        doc.Add(DetailTable); 

        var SignatureTable = new PdfPTable(3);
        SignatureTable.HorizontalAlignment = 0;
        SignatureTable.SpacingBefore = 10;
        SignatureTable.SpacingAfter = 10;
        SignatureTable.SetWidths(new int[] { 6, 6, 6 });
        SignatureTable.WidthPercentage = 100;
        SignatureTable.DefaultCell.Border = Rectangle.BOX; 

        SignatureTable.AddCell(CreateLeftAlignedCell("Prepared By:", TableHeaderFont, 1));
        SignatureTable.AddCell(CreateLeftAlignedCell("Checked By: ", TableHeaderFont, 1));
        SignatureTable.AddCell(CreateLeftAlignedCell("Approved By:", TableHeaderFont, 1)); 

        PdfPCell cell1 = new PdfPCell(new Phrase(PurchaseInvoices.First().MstUser.FullName, BodyFont)) { HorizontalAlignment = PdfPCell.ALIGN_CENTER, VerticalAlignment = PdfPCell.ALIGN_BOTTOM };
        PdfPCell cell2 = new PdfPCell(new Phrase(PurchaseInvoices.First().MstUser1.FullName, BodyFont)) { HorizontalAlignment = PdfPCell.ALIGN_CENTER, VerticalAlignment = PdfPCell.ALIGN_BOTTOM };
        PdfPCell cell3 = new PdfPCell(new Phrase(PurchaseInvoices.First().MstUser2.FullName, BodyFont)) { HorizontalAlignment = PdfPCell.ALIGN_CENTER, VerticalAlignment = PdfPCell.ALIGN_BOTTOM }; 

        cell1.FixedHeight = 50f;
        cell2.FixedHeight = 50f;
        cell3.FixedHeight = 50f; 

        SignatureTable.AddCell(cell1);
        SignatureTable.AddCell(cell2);
        SignatureTable.AddCell(cell3); 

        doc.Add(SignatureTable); 

        doc.Close();
    }
    catch { } 

    byte[] file = stream.ToArray();
    MemoryStream output = new MemoryStream();
    output.Write(file, 0, file.Length);
    output.Position = 0; 

    return output;
}

Now it may look gruesome at first, because it is 100% hardcore code to create a report, but once you start writing it down you will get a familiarity of the ITextPDF libraries, which is very powerful and customizable, the code will be clearer and understandable.  I hightlighted a single line above because this line is optional, it is just merely overloading the PdfPageEventHelper class to create a header and footer of the report.  I will discuss this soon in my future blogs.

In order also to fully understand the code, below is the sample actual output report created by the code.

And the last step is to call the controller in your views, it turns out, it is very simple as shown in the sample Javascript code below.

function cmdPrint_onclick()
   {
      if ($Id > 0)
      {
         window.location.href = '/api/SysReport?Report=PurchaseInvoice?Id=' + $Id;
      }
}

Hope this blog helpful.