5

I'm doing mvc reporting and i'm very new at it. I'm trying to create a report, and i have done it using rdlc. Everything works well, it can be exported to various format. My problem, when using rdlc is that we need to design and bind it first. How can i create an empty rdlc template, design and bind it with dataset programmatically.

My work so far (using empty rdlc template - just created the file without any table),

Controller File,

public ActionResult Report(string id)
    {
        DB.Open();
        LocalReport lr1 = new LocalReport();
        string path1 = Path.Combine(Server.MapPath("~/Report"), "TestEmptyReport.rdlc");
        lr1.ReportPath = path1;
        DataTable pc2a = new DataTable();
        pc2a = DB.getDataSet().Tables[0];
        pc2a.Columns.Add("Product Name");
        pc2a.Columns.Add("Price");
        pc2a.Columns.Add("Quantity");
        ReportDataSource rdc = new ReportDataSource("DataSet1", pc2a);
        lr1.DataSources.Add(rdc);

        string reportType = id;
        string mimeType;
        string encoding;
        string fileNameExtension;

        string deviceInfo =

            "<DeviceInfo>" +
            "<OutputFormat>" + id + "</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;

        renderedBytes = lr1.Render(
            reportType,
            deviceInfo,
            out mimeType,
            out encoding,
            out fileNameExtension,
            out streams,
            out warnings);

        return File(renderedBytes, mimeType);

    }

Model File,

public DataSet getDataSet()
    {
        string query = "SELECT * FROM tblproduct";
        if (con.State.ToString() == "Open")
        {
            SqlDataAdapter ad = new SqlDataAdapter(query, con);
            DataSet ds = new DataSet("tblproduct");

            ad.Fill(ds);

            return ds;
        }
        else
        {
            return null;
        }
    }

View File,

<div style="padding: 10px; border: 1px solid black">
<div><a href="@Url.Action("Report", new { id = "PDF" })">Get PDF Report</a></div>
<div><a href="@Url.Action("Report", new { id = "Excel" })">Get Excel Report</a></div>
<div><a href="@Url.Action("Report", new { id = "Word" })">Get Word Report</a></div>
<div><a href="@Url.Action("Report", new { id = "Image" })">Get Image Report</a></div>

The data is there, but i just dont know how to connect it with rdlc. Means creating column based on the data and fill it with the data called from sql server.

TQVM in advanced. Explanation and example or any other method will be helpful.

Arif Sam
  • 281
  • 1
  • 8
  • 26
  • What real problem are you trying to address? You can't realistically design a report when you can't even look at it, that's why report designers are important. You *can* bind it to a different data source though. Are you trying to change the columns at runtime? – Panagiotis Kanavos Nov 10 '16 at 08:54
  • On the other hand, an RDLC is just XML. You can generate its contents in the same way as any other XML file, eg use XSLT transformations on an existing XML template file, use Linq to XML to do the same etc. Better do that at *build-time* though, to ensure the results look OK. Getting colors, widths and margins right can be rather annoying – Panagiotis Kanavos Nov 10 '16 at 08:56
  • @PanagiotisKanavos Sorry if my question is unclear. How i imagine it to works is that i create an empty rdlc file, read data from database and create column based on the data received. Yes, as you said, im trying to change columns at runtime, because if theres various different report to be created, its inefficient to create separate rdlc file based on the database table received. – Arif Sam Nov 10 '16 at 09:03
  • I completely forgot that the Report component is fully programmable. You *can* create it at runtime, just like a form by adding controls. Easier that modifying XML *but* you could also use a build script to generate multiple reports from a template report – Panagiotis Kanavos Nov 10 '16 at 09:07
  • On the other hand, you *can* hide columns on a single report, based on expressions (which can use report parameters). You can also remove columns from an existing template report before rendering – Panagiotis Kanavos Nov 10 '16 at 09:09
  • How do you intend to use this? Allowing the user to select columns at runtime does require runtime modification. Having a lot of similar reports whose rows don't change at runtime doesn't. Making the columns configurable by an admin, probably does – Panagiotis Kanavos Nov 10 '16 at 09:11
  • @PanagiotisKanavos just as a friendly reminder, im really new to this. So i might not understand much on the terms. lol. I just understand what you meant by runtime, and im wrong on my last response, not on my runtime. Fyi, im passing my work to someone else, thus im trying to make it easy to integrate. That means he doesnt need to create a new rdlc file and design it. The columns will be read from the code and created in the rdlc. Just need to pass sql statement to the method. – Arif Sam Nov 10 '16 at 09:18
  • That's more involved: A report can bind to anything, even objects and you already pass an arbitrary datatable. You could simply remove the columns you don't want from the DataTable. Changing the SELECT statement though is best left to ORM (eg EF) and microORM tools like Dapper. You *can* use these, because you are loading a full DataTable. In any case, this is an ADO.NET question, not directly related to RDLC – Panagiotis Kanavos Nov 10 '16 at 09:23
  • [Someone already asked how to use Dapper with RDLC](http://stackoverflow.com/questions/17755373/report-viewer-x-dapper) – Panagiotis Kanavos Nov 10 '16 at 09:25
  • @PanagiotisKanavos Thx a lot, ill try to research more on your suggestion. Edited the tag. – Arif Sam Nov 10 '16 at 09:26

2 Answers2

2

If I understand your question correctly you wanted to create a report from a blank RDLC. You have to tell a RDLC file about the data in the design time. You can customize the report in the design time by adding columns or columns from another table or make a join.

Whereas Dynamic RDLC Generator through C# would be there to generate the report dynamically from RDLC. Since the complete ReportingEngine has been custom made but very generic. Copy paste might be going to help generating the report.

Mohit S
  • 13,723
  • 6
  • 34
  • 69
2

Your question implies that you need to generate RDLC report on runtime mode. Things you should remember to:

  1. RDLC report viewer uses Microsoft.ReportViewer.WebForms and Microsoft.Reporting.WebForms namespaces, which utilizing WebForms logic code to bind and render the report. You can use a partial view which acts as container for ASPX page (either using single page or page with code behind) to render the report in MVC view pages.

    NB: You can use ReportViewer instance in controller action method to render RDLC as PDF file and returning FileContentResult (see here).

  2. RDLC contains XML tags which can be generated from various XML builder classes (see MSDN Report Definition for details).

Hence, you may create ReportViewer instance first, e.g.:

using Microsoft.Reporting.WebForms;

protected void Form_Load(Object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        ReportViewer1.ProcessingMode = ProcessingMode.Local;
        ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Report.rdlc");

        // add your DataSet here

        var data = new DataTable(); // example data source
        var dataSource = new ReportDataSource(DataSetName, data);

        ReportViewer1.LocalReport.DataSources.Add(dataSource);

        // put rendering stuff here
    }
}

Then, use steps from Generating RDLC Dynamically for the Report Viewer Local Report example (WebForms is similar to WinForms in terms of event handling usage, thus may be applicable in ASPX page) to create corresponding XML tags which generates report structure, summarized as below.

  1. Create and add DataSet for usage in DataSources element.
  2. Create report body and report items element.
  3. Create Tablix and TablixCorner elements according to table structure inside DataSet.
  4. Create TablixColumn, TablixRow and TablixCell elements which includes Textbox control depending to each column data types. The Value element inside Textbox control should contain expression =Fields!(ColumnName).Value for database-bound columns.
  5. Create report property elements (dataset query, fields, etc.)
  6. Add LoadReportDefinition into ASPX page after all report elements generated properly.

Alternatively, if you already know entire RDLC element structure, the similar solution using XmlWriter class can generate required elements for building the report from scratch, then rename generated XML to RDLC extension and bind it for ReportViewer control (seems takes some time to build each RDLC elements).

Additional references:

Rendering an RDLC report in HTML in ASP.NET MVC

Dynamic Reports with Reporting Services

Community
  • 1
  • 1
Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61