Monday, April 15, 2013

How to Create Asp.Net MVC 3 Report ?


What is iTextSharp ?
  • iTextSharp is a free C# PDF library that is ported from the Java-PDF library iText
  • iText was launched in 2000 and is a popular Open Source Java library
  • iTextSharp has been under development since 2008

What does iTextSharp do ?
  • Generate documents and Reports based on data from an XML file or a database
  • Create maps and books, exploiting numerous interactive features available in PDF
  • Add bookmarks, page numbers, watermarks, and other features to existing PDF documents
  • Split or concatenate pages from existing PDF files
  • Fill out interactive forms
  • Serve dynamically generated or manipulated PDF documents to a web browser

How to Create a Report ?

Step 1 : Open Visual Studio 2010

Step 2 : File ==> New Project as MvcPDFReport


New Project as MvcPDFReport


Step 3 : Select "Internet Application" Project Template

Select "Internet Application" Project Template


After above Steps :

Complete project


Step 4 : After that File ==> Add ==> New Project


New Project

Step 5 : Visual C# ==> Class Library as iTextSharpReportGenerator

Class Library as iTextSharpReportGenerator


After All above Steps :
Complete project


How to Create  iTextSharp Report API ?

Step 1 : Download iTextSharp DLL

Download iTextSharp DLL

Step 2 : Extract above Zip File is as below

Extract above Zip File is as below

Below Steps for "iTextSharpReportGenerator" Class Library Project

Step 1 : Add References for the itextsharp.dll , System.Web and System.Web.Mvc
             
Add References

Step 2 : Add ==> New Class as PdfViewController

PdfViewController.cs 

using System.Web.Mvc;

namespace iTextSharpReportGenerator
{
 /// <summary>
 /// Extends the controller with functionality for rendering PDF views
 /// </summary>
 public class PdfViewController : Controller
 {
   private readonly HtmlViewRenderer _htmlViewRenderer;
   private readonly StandardPdfRenderer _standardPdfRenderer;

   public PdfViewController()
   {
      this._htmlViewRenderer = new HtmlViewRenderer();
      this._standardPdfRenderer = new StandardPdfRenderer();
   }

  protected ActionResult ViewPdf(string pageTitle,string viewName,object model)
  {
   // Render the view html to a string
   var htmlText = this._htmlViewRenderer.RenderViewToString(this,viewName,model);

   // Let the html be rendered into a PDF document through iTextSharp
   byte[] buffer = _standardPdfRenderer.Render(htmlText, pageTitle);

   // Return the PDF as a binary stream to the client
   return new BinaryContentResult(buffer, "application/pdf");
  }
 }
}


Step 3 : Add ==> New Class as BinaryContentResult

BinaryContentResult.cs

using System.IO;
using System.Web;
using System.Web.Mvc;

namespace iTextSharpReportGenerator
{
    /// <summary>
    /// An ActionResult used to send binary data to the browser
    /// </summary>
    public class BinaryContentResult : ActionResult
    {
        private readonly string _contentType;
        private readonly byte[] _contentBytes;

        public BinaryContentResult(byte[] contentBytes, string contentType)
        {
            this._contentBytes = contentBytes;
            this._contentType = contentType;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            var response = context.HttpContext.Response;
            response.Clear();
            response.Cache.SetCacheability(HttpCacheability.Public);
            response.ContentType = this._contentType;

            using (var stream = new MemoryStream(this._contentBytes))
            {
                stream.WriteTo(response.OutputStream);
                stream.Flush();
            }
        }
    }
}

Step 4 : Add ==> New Class as StandardPdfRenderer

StandardPdfRenderer.cs

using System.IO;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;

namespace iTextSharpReportGenerator
{
  /// <summary>
  /// This class is responsible for rendering a html text string to a PDF 
  /// document using the html renderer of iTextSharp
  /// </summary>
 public class StandardPdfRenderer
 {
   private const int HorizontalMargin = 40;
   private const int VerticalMargin = 40;

   public byte[] Render(string htmlText, string pageTitle)
   {
     byte[] renderedBuffer;

     using (var outputMemoryStream = new MemoryStream())
      {
        using (var pdfDocument = new Document(PageSize.A4, HorizontalMargin, HorizontalMargin, VerticalMargin, VerticalMargin))
       {
        PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, outputMemoryStream);
        pdfWriter.CloseStream = false;
        pdfWriter.PageEvent = new PrintHeaderFooter { Title = pageTitle };
        pdfDocument.Open();
        using (var htmlViewReader = new StringReader(htmlText))
         {
           using (var htmlWorker = new HTMLWorker(pdfDocument))
            {
               htmlWorker.Parse(htmlViewReader);
            }
         }
       }

        renderedBuffer = new byte[outputMemoryStream.Position];
        outputMemoryStream.Position = 0;
        outputMemoryStream.Read(renderedBuffer, 0, renderedBuffer.Length);
     }

     return renderedBuffer;
   }
  }
  }


Step 5 : Add ==> New Class as FakeView

FakeView.cs

using System;
using System.IO;
using System.Web.Mvc;

namespace iTextSharpReportGenerator
{
    /// <summary>
    /// Defines the FakeView type
    /// </summary>
    public class FakeView : IView
    {
        public void Render(ViewContext viewContext, TextWriter writer)
        {
            throw new NotImplementedException();
        }

    }
}


Step 6 : Add ==> New Class as PrintHeaderFooter

PrintHeaderFooter.cs

using System;
using System.Globalization;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpReportGenerator
{
    /// <summary>
    /// This class represents the standard header and footer for a PDF print
    /// application by Extending the PdfPageEventHelper (iTextSharp Class)
    /// </summary>
    public class PrintHeaderFooter : PdfPageEventHelper
    {
      private PdfContentByte _pdfContent;
      private PdfTemplate _pageNumberTemplate;
      private BaseFont _baseFont;
      private DateTime _printTime;

      public string Title { get; set; }

      public override void OnOpenDocument(PdfWriter writer, Document document)
      {
        _printTime = DateTime.Now;
        _baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
        _pdfContent = writer.DirectContent;
        _pageNumberTemplate = _pdfContent.CreateTemplate(50, 50);
      }

      public override void OnStartPage(PdfWriter writer, Document document)
       {
         base.OnStartPage(writer, document);
         Rectangle pageSize = document.PageSize;

         if (Title != string.Empty)
          {
            _pdfContent.BeginText();
            _pdfContent.SetFontAndSize(_baseFont, 11);
            _pdfContent.SetRGBColorFill(0, 0, 0);
            _pdfContent.SetTextMatrix(pageSize.GetLeft(40), pageSize.GetTop(40));
            _pdfContent.ShowText(Title);
            _pdfContent.EndText();
          }
        }

      public override void OnEndPage(PdfWriter writer, Document document)
      {
         base.OnEndPage(writer, document);
         int pageN = writer.PageNumber;
         string text = pageN + " - ";
         float len = _baseFont.GetWidthPoint(text, 8);

         Rectangle pageSize = document.PageSize;
         _pdfContent = writer.DirectContent;
         _pdfContent.SetRGBColorFill(100, 100, 100);

         _pdfContent.BeginText();
         _pdfContent.SetFontAndSize(_baseFont, 8);
         _pdfContent.SetTextMatrix(pageSize.Width / 2, pageSize.GetBottom(30));
         _pdfContent.ShowText(text);
         _pdfContent.EndText();

         _pdfContent.AddTemplate(_pageNumberTemplate, (pageSize.Width / 2) + len, pageSize.GetBottom(30));

          _pdfContent.BeginText();
          _pdfContent.SetFontAndSize(_baseFont, 8);
          _pdfContent.ShowTextAligned(PdfContentByte.ALIGN_RIGHT, _printTime.ToString(CultureInfo.InvariantCulture), pageSize.GetRight(40), pageSize.GetBottom(30), 0);
          _pdfContent.EndText();
       }

       public override void OnCloseDocument(PdfWriter writer, Document document)
       {
          base.OnCloseDocument(writer, document);

          _pageNumberTemplate.BeginText();
          _pageNumberTemplate.SetFontAndSize(_baseFont, 8);
          _pageNumberTemplate.SetTextMatrix(0, 0);
          _pageNumberTemplate.ShowText(string.Empty + (writer.PageNumber - 1));
          _pageNumberTemplate.EndText();
       }
    }
}


Step 7 : Add ==> New Class as HtmlViewRenderer 

HtmlViewRenderer.cs

using System.IO;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace iTextSharpReportGenerator
{
    /// <summary>
    /// This class is responsible for rendering a HTML view into a string
    /// </summary>
    public class HtmlViewRenderer
    {
      public string RenderViewToString(Controller controller, string viewName, object viewData)
       {
          var renderedView = new StringBuilder();
          using (var responseWriter = new StringWriter(renderedView))
          {
            var fakeResponse = new HttpResponse(responseWriter);
            var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
            var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), controller.ControllerContext.RouteData, controller.ControllerContext.Controller);

             var oldContext = HttpContext.Current;
             HttpContext.Current = fakeContext;

             using (var viewPage = new ViewPage())
              {
               var html = new HtmlHelper(CreateViewContext(responseWriter, fakeControllerContext), viewPage);
               html.RenderPartial(viewName, viewData);
               HttpContext.Current = oldContext;
              }
          }

        return renderedView.ToString();
      }

      private static ViewContext CreateViewContext(TextWriter responseWriter, ControllerContext fakeControllerContext)
       {
         return new ViewContext(fakeControllerContext, new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), responseWriter);
       }
   }
}

After above Steps Class Library Project is as below


Complete project

Class Diagram for above Report API


Class Diagram for above Report API


How to use Above Report API in MVC 3 Project (i.e. MvcPDFReport)?

Step 1 : Add ==> New Class as Provider inside the Model Folder

Provider.cs

namespace MvcPDFReport.Models
{
    /// <summary>
    /// Provider model
    /// </summary>
    public class Provider
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public string Place { get; set; }
    }
}

  
Step 2 : Add ==> New Class as ProviderList inside the Model Folder

ProviderList.cs

using System.Collections.Generic;

namespace MvcPDFReport.Models
{
    /// <summary>
    /// ProviderList model which extends Provider collection
    /// </summary>
    public class ProviderList : List<Provider>
    {
        public string ImageUrl { get; set; }
    }
}


Step 3 : Extends the PdfViewController functionality on HomeController

HomeController.cs

using System.Web.Mvc;
using MvcPDFReport.Models;
using iTextSharpReportGenerator;

namespace MvcPDFReport.Controllers
{
 /// <summary>
 /// Extends the PdfViewController with functionality for rendering PDF views
 /// </summary>
 public class HomeController : PdfViewController
  {
   public ActionResult PrintProviders()
   {
     var providerList = CreateCustomerList();
     FillImageUrl(providerList, "iTextSharp.png");
     return this.ViewPdf("Software Providers Report", "PdfReport", providerList);
   }

   #region Private Methods

   private void FillImageUrl(ProviderList providerList, string imageName)
   {
     if (Request.Url == null) return;
     var url = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
     providerList.ImageUrl = url + "Content/" + imageName;
   }

   private ProviderList CreateCustomerList()
   {
   return new ProviderList()
    {
    new Provider {Id=1,Name="Inexis Consulting",Address="Colombo 4",Place="Sri Lanka"},
    new Provider {Id=2,Name="Microsoft",Address ="Washington",Place="USA"},
    new Provider {Id=3,Name="IBM",Address="Armonk, New York",Place="USA" },
    new Provider {Id=4,Name="HP",Address="California",Place="USA"},
    new Provider {Id=5,Name="Novell",Address="Provo,Utah",Place="USA"},
    new Provider {Id=6,Name="Google",Address="California",Place="USA"},
    new Provider {Id=7,Name="Oracle",Address="Redwood City",Place="USA"},
    new Provider {Id=8,Name="Apple",Address="California",Place="USA"},
    new Provider {Id=9,Name="SAP",Address="Walldorf",Place="Germany"},
   };
  }
  #endregion
 }
}

Step 4 : Add ==> View as PdfReport inside the Home Folder  

PdfReport.cshtml

@using MvcPDFReport.Models
@model ProviderList
<br />
<img src="@Model.ImageUrl" width="64" height="64" />
<br />
<table cellpadding="3" cellspacing="3">
    <tr border="1" bgcolor="#777777" color="#ffffff">
        <td width="20%" align="center">
            Provider Name
        </td>
        <td width="50%" align="center">
            Provider Address
        </td>
        <td width="30%" align="center">
            Provider Place
        </td>
    </tr>
    @{
        var oddColor = "#FACC6D";
        var evenColor = "#99CC33";
        var odd = oddColor;
    }
    @foreach (var p in Model)
    {
        <tr border="1" bgcolor="@odd">
            <td>@p.Name
            </td>
            <td>@p.Address
            </td>
            <td>@p.Place
            </td>
        </tr>
       
        odd = odd == oddColor ? evenColor : oddColor;
    }
</table>

Step 5 : Add Hyper Link for the Index View

Index.cshtml

@{
    ViewBag.Title = "Home Page";
 }

<h2>Press the link to print a Software Provider List to PDF</h2>

@Html.ActionLink("Print Software Providers", "PrintProviders", null, new { target = "_blank" })


After above Steps MVC project is as below


Complete project


What is the Final Look of the Report

Screen 1 :

Final Look of the Report
   

Screen 2 :

Final Look of the Report


How to do Print,Zoom,Page Navigation,Save etc.. ?

On Chrome - When You Move the Mouse Right Bottom side of the Report

On Chrome

On Firefox - Top of the Report

On Firefox


On Internet Explorer - When You Move the Mouse Bottom of the Report

On Internet Explorer


Do You Need to Know More about iTextSharp ?

Do You Need a Book ?



Do You Need to Download this Sample Project ?

Download


Conclusion
  • You can see that it's very easy to create MVC Reports by using iTextSharp
  • It's having lot of inbuilt features to make your job very easy
  • Such as iTextsharp supports colors out of the box as you can see on above report
  • It is possible to add images to the report by using an <img src="" /> tag

I hope this helps to You.Comments and feedback greatly appreciated.

If you feel it was a good article,Give me a +1.Thank You.




Happy Coding.


You Might Also Like

How to Improve ASP.Net MVC 3 View Performance ?