5

I am fairly new to ASP.Net MVC. I have a requirement of showing an RDLC based report in MVC.

Basically my requirement as well as what I have done is :-

I have a ReportController inheriting APIController, which has a method that returns a DataSet. This DataSet is being sent to the RDLC file.

For this, I have done the following, but could not make the report work.

I have created a model class named ReportParameter as follows:

public class ReportParameter 
{
    public DateTime DateFrom { get; set; }
    public DateTime DateTo { get; set; }
}

I have the following controller ReportViewController :

public class ReportViewController : Controller
{
    static readonly ReportController ctrl = new ReportController();

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

    [HttpPost]
    public ActionResult GenerateReport(ReportParameterSalesOrder param)
    {
        if (ModelState.IsValid)
        {
            Helpers.DataLayer dl = new Helpers.DataLayer();
            if (param.DateFrom != null)
            {
                DateTime DateFrom = Convert.ToDateTime(param.DateFrom);
                DateTime DateTo = Convert.ToDateTime(param.DateTo);

                string fdate = DateFrom.ToString("yyyy/MM/dd");
                string tdate = DateTo.ToString("yyyy/MM/dd");

                Session["ReportSales"] = ctrl.ReportSales(param);
            }

            return Redirect(Url.Action("ViewReport", "ReportView"));
        }
        return View();
    }
    public ActionResult ViewReport()
    {
         return View();
    }

}

I have an API Controller ReportController whose object has been created in the above ReportViewerController to generate a DataSet and to populate the RDLC report. The API Controller is:

public class ReportController : ApiController
{

    static readonly IReportRepository repository = new ReportRepository();

    [ActionName("ReportSales")]
    public DataSet ReportSales(ReportParameterSalesOrder paramSO)
    {
        DataSet item = repository.ReportSales(paramSO);
        if (item == null)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        return item;
    }
}

I have two views GenerateReport.aspx and ViewReport.aspx. The GenerateReport.aspx is given below:

<table style="width: 40%;">
              <tr>
                  <td class="style1">
                      <h3>
                          <asp:Label ID="Label1" runat="server" Text="From Date"></asp:Label></h3>
                  </td>
                  <td>
                      <%=@Html.EditorFor(a=> a.DateFrom, new{id="startDate",style="width:250px;"}) %>
                      <%=@Html.ValidationMessageFor(a => a.DateFrom)%>
                  </td>
              </tr>
              <tr>
                  <td class="style1">
                      <h3>
                          <asp:Label ID="Label2" runat="server" Text="To Date"></asp:Label></h3>
                  </td>
                  <td>
                      <%=@Html.EditorFor(a => a.DateTo, new { id = "ToDate", style = "width: 250px;" })%>
                      <%=@Html.ValidationMessageFor(a => a.DateTo)%>
                  </td>
              </tr>
              <tr>
                  <td class="style1">
                      &nbsp;
                  </td>
                  <td>
                      &nbsp;
                  </td>
              </tr>
              <tr>
                  <td class="style1">
                      &nbsp;
                  </td>
                  <td>
                      <input id="btnsearch" class="button" type="submit" value="Show" />
                  </td>
              </tr>
          </table>

The ViewReport.aspx is given below:

 <center style="width: 974px">
      <iframe id="myReport" width="100%" height="450px" src="ReportViewer.aspx">

        </iframe></center>

I have added a Dataset.xsd, an rdlc file and an aspx page to add the rdlc file.

But I cannot make it work. How do I display the report, or how do I populate the dataset that I receive from the Controller to the report ?

StuartLC
  • 104,537
  • 17
  • 209
  • 285
Nubicus
  • 55
  • 1
  • 1
  • 7
  • 1
    The `ViewReport.aspx` used in the `iframe` will need to be a good old fashioned web form with code behind - e.g. set the DataSet in the code behind `ViewReport.aspx.cs`. What you can probably do is pass the data from the MVC Controller via the `Session[]` variable? – StuartLC Jan 01 '15 at 09:40
  • The ViewReport.aspx doesn't have a code behind file. Can you explain a bit more ? – Nubicus Jan 01 '15 at 09:49

1 Answers1

5

Background
(I know you know this, but for future readers ;-)

  • The Microsoft ReportViewer Control requires ViewState and WebForms ScriptManagers to work correctly, and as such isn't suited for direct use in MVC Views.
  • It is however possible to run a WebForms page in an MVC Project - as they run in the same AppDomain, Session state is shared between MVC and WebForms.

In Detail
The ViewReport.aspx page used to render the ReportViewer control in the iframe on the MVC View will need to be a good old fashioned asp.Net web form.

For small data sets, you can fetch the report data in the MVC Controller and then pass this in Session across to the WebForm.

However, for larger data sets, I would recommend that you instead pass the Parameters across to the WebForm in Session (or even via the QueryString, if they aren't sensitive), and then the WebForm code behind would need to fetch the data set and bind it to the ReportViewer.

On the MVC Side, in the MyController parameter post:

    [HttpPost]
    public ActionResult GenerateReport(string param1, int param2)
    {
        // Obviously you apply the parameters as predicates and hit the real database
        Session["ReportData"] = FakeDatabaseData;
        ViewBag.ShowIFrame = true;
        return View();
    }

You can show the IFrame once the ReportParameters have been typed in by the user, on the View, MyController/GenerateReport:

<iframe src='<%= Url.Content("~/OldSkoolAspx/ReportViewer.aspx") %>' width="100%" height="450px"></iframe>

Then add a WebForms page /OldSkoolAspx/ReportViewer.aspx to your MVC project. In the code behind ReportViewer.aspx.cs:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            var reportDataSource = new ReportDataSource
            {
                // Must match the DataSource in the RDLC
                Name = "SomeReportDataSet",
                Value = Session["ReportData"]
            };
            ReportViewer1.LocalReport.DataSources.Add(reportDataSource);
            ReportViewer1.DataBind();
        }
    }

And in the WebForms ReportViewer.aspx front end, add the control (recommend use the toolbox, so all the requisite references get added to the web.config):

    <rsweb:ReportViewer ID="ReportViewer1" runat="server" Font-Names="Verdana" Font-Size="8pt" WaitMessageFont-Names="Verdana" WaitMessageFont-Size="14pt" Width="476px">
        <LocalReport ReportPath="MyReport.rdlc">
        </LocalReport>
    </rsweb:ReportViewer>
    <asp:ScriptManager runat="server" ID="SillyPrerequisite"></asp:ScriptManager>

There's a lot of moving parts here, so I've uploaded a demo project to GitHub over here

Note that the same technique will also work for Report Server generated reports (i.e. using ReportViewer with .RDL reports). Do however be wary that both RDLC and RDL can be real SessionState hogs

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Thanks @StuartLC, you made my day. I was scratching my head for a while to show a report. – Nubicus Jan 05 '15 at 07:26
  • Hi but the thing is when my report loads the other functionality is blocked even i tried asnycrender to true bt all the functionalites work only after the report is completely loaded any clue for that? – rohit singh May 06 '15 at 11:23
  • Man,it helped me out big time. :) – ksg Apr 02 '16 at 06:38