# Returning a Crystal report as a PDF ActionResult in ASP.Net MVC

In a recent project I needed to display a generated PDF contract document inside the browser. I found a [great article by Patrick Kalkman](http://www.codeproject.com/Articles/260470/PDF-reporting-using-ASP-NET-MVC) illustrating how to create a custom ActionResult that converts a HTML string into a PDF using the iTextSharp library.

This seemed like the perfect solution, however, I later found that the conversion from HTML to PDF is not perfect at all and getting your design to look the same in PDF as it does in HTML is not easy. So I found another [article by Hasibul Haque](http://hasibulhaque.com/index.php/2011/crystal-report-asp-net-mvc/), where he shows how to return a Crystal Report as PDF using ASP.Net MVC.

The Crystal Report approach works well, as your design will look perfect. The only problem I had was Hasibul’s approach returned the PDF as a download and I wanted to display it inside the browser. I combined Patrick and Hasibul’s approaches and what I came up with was a **CrystalReportPdfResult**

The CrystalReportPdfResult is an ASP.Net ActionResult, that return the Crystal Report as a PDF file. The result (using an iframe) looks like this inside the browser:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1664278218642/Tpd6xP318.png align="left")

#### Creating the CrystalReportPdfResult class

To generate the result as indicated by the previous image, follow these steps:

1.  Create a folder inside your ASP.Net MVC project called **Pdf**.
2. Add a new class to this folder called **CrystalReportPdfResult.cs**.
3. The new class will inherit from the ASP.Net MVC **ActionResult** class.

The entire code listing for the CrystalReportPdfResult class follows:

CrystalReportPdfResult.cs

```csharp
public class CrystalReportPdfResult : ActionResult
{
    private readonly byte[] _contentBytes;

    public CrystalReportPdfResult(string reportPath, object dataSet)
    {
        ReportDocument reportDocument = new ReportDocument();
        reportDocument.Load(reportPath);
        reportDocument.SetDataSource(dataSet);
         _contentBytes = StreamToBytes(reportDocument.ExportToStream(ExportFormatType.PortableDocFormat));
     }

     public override void ExecuteResult(ControllerContext context)
     {

         var response = context.HttpContext.ApplicationInstance.Response;
         response.Clear();
         response.Buffer = false;
         response.ClearContent();
         response.ClearHeaders();
         response.Cache.SetCacheability(HttpCacheability.Public);
         response.ContentType = "application/pdf";

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

     private static byte[] StreamToBytes(Stream input)
     {
         byte[] buffer = new byte[16 * 1024];
         using (MemoryStream ms = new MemoryStream())
         {
             int read;
             while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
             {
                 ms.Write(buffer, 0, read);
             }
             return ms.ToArray();
         }
     }
 }
```

#### Creating the Crystal Report

Next, we need to create the Crystal Report that will be returned as a PDF. Do this by following these steps:

1.  Create a new folder called **Reports** in your project.
2.  Add a new Crystal Report object to the **Reports** folder. You can find the item template under the **Reporting** tab on the Add New Item dialog.
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1664278282639/whD060PhG.png align="left")
3.  Design the report to your liking and save it.
4.  If you need to install Crystal Reports for Visual Studio 2013, get it [here](http://scn.sap.com/docs/DOC-7824).

#### Creating the Action that will return the PDF

Next, we need to create the actual Action on a Controller that will return the CrystalReportPdfResult, by following these steps:

1.  Open your controller. In this example, we’ll use the **HomeController**.
2.  Add a new method called **Pdf** that will return a **CrystalReportPdfResult** object.
3.  Inside this method, we’ll build a list of customer that will be used as data for the report and build the path to the report filename. The code for the method follows:

```csharp
public CrystalReportPdfResult Pdf()
{
    List<Customer> model = new List<Customer>();
    model.Add(new Customer { CompanyName = "Blah Inc.", ContactName = "Joe Blogs" });
    string reportPath = Path.Combine(Server.MapPath("~/Reports"), "rptCustomers.rpt");
    return new CrystalReportPdfResult(reportPath, model);
}
```

#### Creating the View

We’ll embed the PDF using an **<iframe>**, so open a view. In this case we’ll  use **About.cshtml** and replace it’s mark-up with the following:

About.cshtml

```razor
@{
    ViewBag.Title = "Customer Report";
}
<h2>@ViewBag.Title.</h2>
<p>This is the customer report</p>

<div class="row">
    <div class="col-md-10">
         <iframe src="@Url.Action("Pdf", "Home")" height="500" width="100%"></iframe>
     </div>
     <div class="col-md-2">
         <h3>Other page content</h3>
         <button type="button" class="btn btn-primary">Click here</button>
     </div>
 </div>
```

Note, that we’re using the **@Url.Action** helper to set the **src** attribute of the <iframe> element. This will make a call to the **Pdf** action on the **Home** controller and render the result inside the **<iframe>**

In case you’re wondering how to send the Crystal Report as a PDF attachment on an email, here is the code:

Code Snippet

```csharp
public void SendReport()
        {
            List<Customer> model = new List<Customer>();
            model.Add(new Customer { CompanyName = "Blah Inc.", ContactName = "Joe Blogs" });

            ReportDocument reportDocument = new ReportDocument();
            reportDocument.Load(Path.Combine(Server.MapPath("~/Reports"), "rptCustomers.rpt"));
            reportDocument.SetDataSource(model);
            using (var stream = reportDocument.ExportToStream(ExportFormatType.PortableDocFormat))
             {
                 SmtpClient smtp = new SmtpClient
                 {
                     Port = 587,
                     UseDefaultCredentials = true,
                     Host = "smtp.gmail.com",
                     EnableSsl = true
                 };

                 smtp.UseDefaultCredentials = false;
                 smtp.Credentials = new NetworkCredential("you@gmail.com", "gmailPassword");

                 var message = new System.Net.Mail.MailMessage("you@gmail.com", "recipient@gmail.com", "subject", "body");
                 message.Attachments.Add(new Attachment(stream, "report.pdf"));

                 smtp.Send(message);
             }
         }
```

I’ve tested this on the latest version of Chrome, Firefox and Internet Explorer and it works on all of them.

Hope this helps someone that needs something similar. Thank you for reading. Until next time, keep coding!

Download the sample project [here.](https://www.dropbox.com/s/gonervde3avxkgb/PdfSample.zip?dl=0)

If you have any comments or questions, please feel free to ask leave a comment or drop me a line on [Twitter](http://twitter.com/pietervander).
