Thursday, December 31, 2009

Drilling 2 steps in Reports Viewer 2005

Imagine a situation where you have a report that has a link to another report. The other report also has a link to another third report. This sounds logical and easy, and it works perfectly in the report server viewer. But when you try to deploy your reports and view them using the report viewer you have in Visual Studio 2005, it throws an exception:

The path of the item "(null)" is not valid. The path must be less than 260 characters long and must start with slash. Other restrictions apply. (rsInvalidItemPath)

As far as I know, this problem is only available in the report viewer of Visual studio 2005. I worked out a work around for this issue.

The Idea:

You have to handle the event of drilling and tell the report viewer to cancel the event, collect the parameters of the new report and set them, and finally set the report path of the report viewer to the new path. Now you are done. Have a look at the code below.

   1: protected void ReportViewer_Drillthrough(object sender, DrillthroughEventArgs e)
   2: {
   3:     /// This version of the report viewer doesnt support the nested reports
   4:     /// this section is used to rerender the whole thing.
   5:     string[] values = null;
   7:     // Get All possible parameters that this report takes
   8:     ReportParameterInfoCollection reportParms = e.Report.GetParameters();
   9:     // Create an empty list of parameters that i will send
  10:     List<ReportParameter> parms = new List<ReportParameter>();
  11:     foreach (ReportParameterInfo i in reportParms)
  12:     {
  13:         // if the parameter value in nullable, and I didnt choose to send a value
  14:         if (i.Values.Count == 0)
  15:             continue;
  17:         else if (i.Values.Count > 1)
  18:         {
  19:             values = new string[i.Values.Count];
  20:             i.Values.CopyTo(values, 0);
  21:             parms.Add(new ReportParameter(i.Name, values));
  22:         }
  23:         else
  24:         {
  25:             parms.Add(new ReportParameter(i.Name, i.Values[0]));
  26:         }
  27:     }
  29:     // Now reset the viewer, as if its a new request
  30:     ReportViewer.Reset();
  31:     // Cancel the drilling action
  32:     e.Cancel = true;
  33:     // Reset the ReportServerURL, this is optional.
  34:     // If you dont know what to write here, try removing it.
  35:     ReportViewer.ServerReport.ReportServerUrl = new Uri(Session["SSRS Server"].ToString());
  36:     // Set the new report that will be displayed, and set its parameters
  37:     ReportViewer.ServerReport.ReportPath = e.ReportPath;
  38:     ReportViewer.ServerReport.SetParameters(parms);
  39: }

One draw back of this solution, is that the back button of the report viewer is not effective anymore. On the other hand, the browser's back navigation button is effective, and can take you to the previous parent report. However, if you clicked any other link in the parent report, it will throw an exception:

Execution 'vzlnjkfdkub0oan53dig5g55' cannot be found

I thought of a solution, which I don't know is acceptable for you or not, which is disabling the browser's back button using JavaScript (see below), and adding a navigation expression in my report. i.e. adding a textbox in the report, with text something like "<< Back" which jumps to the parent report, and sending the needed parameters.

   1: <script language="javascript" type="text/javascript" >
   2:     history.forward();
   3: </script>