Friday, 11 April 2014

Reports in MVC4


Crystal report in MVC
using CrystalDecisions.CrystalReports.Engine;

public ActionResult Report()
{
    ReportClass rptH = new ReportClass();
    rptH.FileName = Server.MapPath("[reportName].rpt");
    rptH.Load();
    rptH.SetDataSource([datatable]);
    Stream stream = rptH.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
    return File(stream, "application/pdf");  
}

or 

ADD ACTION FOR GENERATE PDF FILE FOR REPORT DATA

Go To Controller > Add your action > write following code and Rebuild your application to get data from Database. 
 public ActionResult ExportReport()
        {
            List<everest> allEverest = new List<everest>();
            using (MyDatabaseEntities dc = new MyDatabaseEntities())
            {
                allEverest = dc.Everests.ToList();
            }

            ReportDocument rd = new ReportDocument();
            rd.Load(Path.Combine(Server.MapPath("~/Reports"), "rpt_EverestList.rpt"));
            rd.SetDataSource(allEverest);

            Response.Buffer = false;
            Response.ClearContent();
            Response.ClearHeaders();


            try
            {
                Stream stream = rd.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
                stream.Seek(0, SeekOrigin.Begin);
                return File(stream, "application/pdf", "EverestList.pdf");
            }
            catch (Exception ex)
            {
                throw;
            }
        }
</everest></everest>


Using MVC(razor) C#. and  using LINQ

your views: 
http://www.codeproject.com/images/minus.gif Collapse | Copy Code
@model sample.Models.Report

@{
    ViewBag.Title = "Report";
}

<script type="text/javascript">
    $(document).ready(function () {
        $('#btnPreview').click(function () {       
            var oParam = { "empCode": "" };

            oParam.empCode = "001";           

            $.ajax({
                url: '@Url.Action("SampleReport","Report")',
                data: JSON.stringify(oParam),
                type: 'POST',
                contentType: 'application/json;',
                dataType: 'json',
                success: function () {
                    window.open('@Url.Action("showRPT", "ReportViewer")', 'mywindow', 'fullscreen=yes, scrollbars=auto');
                }
            });
        });
    });
</script>

@using (Html.BeginForm())
{
<input id = "btnPreview" type="button" value= "Preview" />
}

your model:
http://www.codeproject.com/images/minus.gif Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace sample.Models
{
    public class Report
    {
        public string field1{ get; set; }
        public string field2{ get; set; }
        public string field3{ get; set; }
        public string field4{ get; set; }
        public string field5{ get; set; }       
        public string field6{ get; set; }
        public string field7{ get; set; }       
    }
}

your controller: report
http://www.codeproject.com/images/minus.gif Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using sample.ViewModel;
using sample.Models;

namespace sample.Controllers
{
    public class ReportController : Controller
    {
        //
        // GET: /Report/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public void SampleReport(string empCode)
        {
            this.HttpContext.Session["rptName"] = "bySample.rpt";
            this.HttpContext.Session["empCode"] = empCode.Trim();
            this.HttpContext.Session["rptSource"] = loadRpt(empCode);
        }

private List<Report> loadRpt(string param)
        {
            using (var db = new dbEntities())
            {
                var rptGen = from tblsmpl in db.tblSample
                             where ((tblsmpl.EmpCode.ToLower().Contains(param.ToLower().Trim())))
                             select tblsmpl ;

                List<Report> rptList = new List<Report>();

                foreach (var rptsData in rptGen)
                {
                    rptList.Add(new Report() { field1 = rptsData.field1, field2 = rptsData.field2, field3 = rptsData.field3, field4 = rptsData.field4, field5 = rptsData.field5, field6 = rptsData.field6, field7 = rptsData.field7});
                }

                return (rptList);
            }             
        }
    }
}

your controller: ReportViewer
http://www.codeproject.com/images/minus.gif Collapse | Copy Code
using System.Web.Mvc;
using System;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using sample.Models;
using CrystalDecisions.Web;

namespace sample.Controllers
{
    public class ReportViewerController : Controller
    {
        //
        // GET: /ReportViewer/       
       
        public ActionResult Index()
        {
            return View();
        }

public void showRPT()
        {
            try
            {                               
                bool isValid = true;

                string strReportName = System.Web.HttpContext.Current.Session["rptName"].ToString();
                string strempCode = System.Web.HttpContext.Current.Session["empCode"].ToString();
                var rptSource = System.Web.HttpContext.Current.Session["rptSource"];               

                if (string.IsNullOrEmpty(strReportName))
                {
                    isValid = false;
                }

                if (isValid)
                {
                    ReportDocument rd = new ReportDocument();
                    string strPath = System.Web.HttpContext.Current.Server.MapPath("~/") + "rpt//" + strReportName;
                    rd.Load(strPath);

                    if (rptSource != null && rptSource.GetType().ToString() != "System.String")
                        rd.SetDataSource(rptSource);
                    if (!string.IsNullOrEmpty(empCode))
                        rd.SetParameterValue("empCode", strempCode);
                   
                   
                    rd.ExportToHttpResponse(ExportFormatType.PortableDocFormat, System.Web.HttpContext.Current.Response, false, "crReport");
                    
                    // Clear all sessions value
                    Session["rptName"] = null;
                    Session["empCode"] = null;
                    Session["rptSource"] = null;
                }
                else
                {
                    Response.Write("<H2>Nothing Found; No Report name found</H2>");
                }
            }
            catch (Exception ex)
            {
                Response.Write(ex.ToString());
            }
        }
     }
}




RDLC in MVC

Rendering an RDLC directly to the Response stream in ASP.NET MVC

The following post shows you how to render an RDLC (Client Report Definition File) in a MVC project. For this tutorial, I am using VS 2008 with MVC 2 Beta. I will also be using the priceless Northwind database and the report will contain a list of customers in the Northwind database.

A sample project zip file is provided at the bottom of this post.

We start off by creating an ASP.NET MVC 2 Empty Web Application.
image 
Add a new ADO.NET entity model and choose the option to “Generate from the database”.
 image
image
Choose the connection string to use
image
Choose the database objects (Customers for our scenario) and hit finish. We see that a new entity data model has been created in the Models directory.
image
Create a folder called Content and a subfolder called Reports and add an RDLC into this folder. I hate working with Datasets and hence will not be using the “Report Wizard”. We choose the “Report” template instead.

image
Create a method that returns all the customers in the database through a Customer partial class and add this in the Model folder.

image
using System;
using System.Linq;
using System.Collections.Generic;
 
namespace RDLCRendering.Models
{
    public partial class Customers
    {
        public static List<Customers> GetAllCustomers() {
            var entities = new NorthwindEntities();
            var x = from c in entities.Customers
                    select c;
            return x.ToList();
        }
    }
}

Open  the RDLC. Your UI should look like so (If you don’t see “Website Data Sources”, click on Data –> Show Data Sources):
image
Design your report by adding a table from the toolbox and dragging and dropping fields from the Website Data Sources (reference).
image 
We will now construct our basic MVC web application. The app will have a home screen and a link to view the PDF report of Northwind customers.
Lets start by adding a Home controller
image 
We add the following code in our HomeController class
namespace RDLCRendering.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            string welcomeMessage = "Welcome to Northwind Traders. Enjoy the view!";
            return View((object)welcomeMessage);
        }
    }
}

Right click on the "Index()” method and select “Add View”.

image
Open the Index view and add code to display the string returned and also add a link for the report in the view like so:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<string>" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
        <h2>
            <%=Html.Encode(Model) %></h2>
            
            <%=Html.ActionLink("Customers Report (PDF)", "DetailsReport", "Customers") %>
    </div>
</body>
</html>

Run the application. You should see a UI similar to the one below:
image
If you click on the link you will get a “The resource cannot be found.” error. This is because our Html.Action link refers to a method called “DetailsReport” in a CustomersController which does not exist yet.
Note that we are using the ActionLink overload(linkText, actionName, controllerName).
First add a reference to Microsoft.ReportViewer.WebForms in your project.
image
Add a CustomerController class and add a DetailsReport method like so:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using Microsoft.Reporting.WebForms;
using RDLCRendering.Models;
 
namespace RDLCRendering.Controllers
{
    public class CustomersController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult DetailsReport()
        {
            LocalReport localReport = new LocalReport();
            localReport.ReportPath = Server.MapPath("~/Content/Reports/CustomerReport.rdlc");
            ReportDataSource reportDataSource = new ReportDataSource("Customers", Customers.GetAllCustomers());
 
            localReport.DataSources.Add(reportDataSource);
            string reportType = "PDF";
            string mimeType;
            string encoding;
            string fileNameExtension;
 
            //The DeviceInfo settings should be changed based on the reportType
            //http://msdn2.microsoft.com/en-us/library/ms155397.aspx
            string deviceInfo =
            "<DeviceInfo>" +
            "  <OutputFormat>PDF</OutputFormat>" +
            "  <PageWidth>8.5in</PageWidth>" +
            "  <PageHeight>11in</PageHeight>" +
            "  <MarginTop>0.5in</MarginTop>" +
            "  <MarginLeft>1in</MarginLeft>" +
            "  <MarginRight>1in</MarginRight>" +
            "  <MarginBottom>0.5in</MarginBottom>" +
            "</DeviceInfo>";
 
            Warning[] warnings;
            string[] streams;
            byte[] renderedBytes;
 
            //Render the report
            renderedBytes = localReport.Render(
                reportType,
                deviceInfo,
                out mimeType,
                out encoding,
                out fileNameExtension,
                out streams,
                out warnings);
            //Response.AddHeader("content-disposition", "attachment; filename=NorthWindCustomers." + fileNameExtension);
            return File(renderedBytes, mimeType);
        }
    }
}

This method will create an instance of the LocalReport class, set the Report path property, add a ReportDataSource which points to the GetAllCustomers method we defined earlier, set the report output type and page dimensions, calls the render method and invokes the File method on the Controller class. This method return a FileContentResult which sends the contents of a binary file to the response stream. 
Run the page and click on the link. You should see the PDF report like so:
image

How to render client report definition files (.rdlc) directly to the Response stream without preview


Note: I cover this technique in a more recent post here : Rendering an RDLC directly to the Response stream in ASP.NET MVC 

ReportViewer control is normally used to open a report definition file, process it and load it into the viewing area.
The simple method below allows you to render the report directly to the response stream without using the ReportViewer control. This might be useful in cases where you want to render a non interactive report.
The example below renders the report in PDF format. The other report types available when using the LocalReport.Render method are “Excel”and “Image”.


/// <summary>
/// References:
/// </summary>
private void RenderReport() {
    LocalReport localReport = new LocalReport();
    localReport.ReportPath = Server.MapPath("~/Report.rdlc");
  
    //A method that returns a collection for our report
    //Note: A report can have multiple data sources
    List<Employee> employeeCollection = GetData();

    //Give the collection a name (EmployeeCollection) so that we can reference it in our report designer
    ReportDataSource reportDataSource = new ReportDataSource("EmployeeCollection", employeeCollection);
    localReport.DataSources.Add(reportDataSource);

    string reportType = "PDF";
    string mimeType;
    string encoding;
    string fileNameExtension;

    //The DeviceInfo settings should be changed based on the reportType
    //http://msdn2.microsoft.com/en-us/library/ms155397.aspx
    string deviceInfo =
    "<DeviceInfo>" +
    "  <OutputFormat>PDF</OutputFormat>" +
    "  <PageWidth>8.5in</PageWidth>" +
    "  <PageHeight>11in</PageHeight>" +
    "  <MarginTop>0.5in</MarginTop>" +
    "  <MarginLeft>1in</MarginLeft>" +
    "  <MarginRight>1in</MarginRight>" +
    "  <MarginBottom>0.5in</MarginBottom>" +
    "</DeviceInfo>";

    Warning[] warnings;
    string[] streams;
    byte[] renderedBytes;

    //Render the report
    renderedBytes = localReport.Render(
        reportType,
        deviceInfo,
        out mimeType,
        out encoding,
        out fileNameExtension,
        out streams,
        out warnings);

    //Clear the response stream and write the bytes to the outputstream
    //Set content-disposition to "attachment" so that user is prompted to take an action
    //on the file (open or save)
    Response.Clear();
    Response.ContentType = mimeType;
    Response.AddHeader("content-disposition""attachment; filename=foo." + fileNameExtension);
    Response.BinaryWrite(renderedBytes);
    Response.End();

}


Note that if you change the ReportType in the Render method, you will also have to change the DeviceInfo settings. 

No comments:

Post a Comment