This is a migrated thread and some comments may be shown as answers.

How to load a Report Dynamically

3 Answers 1144 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Manny
Top achievements
Rank 1
Manny asked on 29 Jun 2009, 10:57 PM

I have a generic ASCX control that uses the Telerik ReportViewer and I want to use that for all my reporting output. But, we run into the problem that we need to provide a Report object (as well as ReportParameters) to that viewer control. Here's how I did it:

1. In my case, I know my report assembly. With just a bit more work, the assembly itself could be passed in, but the following still uses reflection to load the report dynamically.

2. ReportParameters are passed in as "Name=Value;[Name=Value;...]" via a single public property named ReportParametersString. Not particularly extensible, but more than sufficient for my simple needs. I handle type coercion (that is, convert from string that is passed into ASCX parameter to specific type supported by Telerik) using the GetTypeFromReportType method. I also have (of course, we all do...) my own DAL (data access layer) using ADO.NET that can convert from just about any input type to any output type (not documented below).

3. In my report assembly, I purposely provide a dummy empty class to make getting the assembly type that much easier.

4. I assume that the report itself can handle its own datasource needs (more on that in another post--I cracked some code to get my own data connection string without needing to modify web.config which is owned by SharePoint not by me...).

5. My ASCX exposes a ReportName property that can be the absolute or relative class name of the report to load.

So here's the code, hope it's useful!

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ArchG2.Portal.rg2SupportingControls.Misc
{
 /// <summary>
 /// Generic reporting viewer for any Telerik report
 /// </summary>
 public partial class TelerikReportViewer : Utils.BaseManageableControl
 {
  private string _reportName;
  private string _prevReportName;
  private Telerik.Reporting.IReportDocument _report;
  private bool _pageIsLoaded;
  private string _reportParametersString;
  private Telerik.Reporting.ReportParameterCollection _reportParameters = new Telerik.Reporting.ReportParameterCollection();
  private TextBox _txtHeight;

  /// <summary>
  /// Handle a resize by applying the resize directly to the control
  /// </summary>
  protected override void resizeHandler()
  {
   if (Width != Unit.Empty)
   {
    // set an explicit width to the report
    rptvw.Width = Width;
   } //if
   if (Height != Unit.Empty)
   {
    // set an explicit height to the report
    rptvw.Height = Height;
   } //if
  } //resizeHandler

  /// <summary>
  /// Invoked whenever the report must definitely be set in the view control.
  /// Will force the view to update / take any other actions.
  /// </summary>
  private void setReport()
  {
   // access our stored report
   Telerik.Reporting.IReportDocument theReport = Report;
   if (theReport == null)
   {
    LH.warn("No report specified; cannot display");
    return;
   } //if

   // set the report itself in the managed viewer
   rptvw.Report = Report;
  } //setReport

  /// <summary>
  /// Given a Telerik reporting type, return a "real" object type so that we can
  /// perform type-safe coercion on data values
  /// </summary>
  /// <param name="reportType">The Telerik report type to convert</param>
  /// <returns>The OS type or an exception if this is an unknown type (new Telerik version could introduce this problem)</returns>
  private Type GetTypeFromReportType(Telerik.Reporting.ReportParameterType reportType)
  {
   switch (reportType)
   {
    case Telerik.Reporting.ReportParameterType.Boolean:
     return typeof(Boolean);
    case Telerik.Reporting.ReportParameterType.DateTime:
     return typeof(DateTime);
    case Telerik.Reporting.ReportParameterType.Float:
     return typeof(double);
    case Telerik.Reporting.ReportParameterType.Integer:
     return typeof(int);
    case Telerik.Reporting.ReportParameterType.String:
     return typeof(string);
    default:
     throw new ApplicationException(
      string.Format("Unknown report type: {0}", reportType.ToString())
     );
   } //switch
  } //GetTypeFromReportType

  /// <summary>
  /// Use reflection to load a given report object from the ArchG2.Reporting assembly.
  /// </summary>
  private void loadReport()
  {
   string flag = "";
   try
   {
    // leverage the Dummy class to get access to the ArchG2.Reporting assembly
    flag = "access_archg2_report";
    Type typeDummy = typeof(ArchG2.Reporting.Dummy);
    System.Reflection.Assembly assemblyArchG2Reporting = typeDummy.Assembly;

    // check to see if the user passed in a full path or a short path
    flag = "load_report";
    string reportToLoad = _reportName;
    int idxDot = reportToLoad.IndexOf('.');
    if (idxDot <= 0)
    {
     string prefix = assemblyArchG2Reporting.GetName().Name;
     if (idxDot < 0) prefix += ".";
     reportToLoad = reportToLoad.Insert(0, prefix);
    } //if
    LH.debug("Loading report ", reportToLoad, " (", _reportName, ")");
    Type typeOfDynamicReport = assemblyArchG2Reporting.GetType(reportToLoad);

    // now instantiate an object of the report; must have default ctor
    flag = "create_report";
    object oReport = Activator.CreateInstance(typeOfDynamicReport);

    // validate the report
    flag = "validate_report";
    Telerik.Reporting.IReportDocument theReport = oReport as Telerik.Reporting.IReportDocument;
    if (theReport == null) throw new ApplicationException("Invalid report type: " + typeOfDynamicReport.Name);

    // now set any parameters on the report
    if (ReportParameters.Count > 0)
    {
     // get the report list
     flag = "access_report_parms";
     List<Telerik.Reporting.ReportParameter> theParameters = theReport.ReportParameters.ToList();

     // build a dictionary
     Dictionary<string, Telerik.Reporting.ReportParameter> theDictionary = new Dictionary<string, Telerik.Reporting.ReportParameter>();
     foreach (Telerik.Reporting.ReportParameter parameter in theParameters)
     {
      theDictionary.Add(parameter.Name.ToUpper(), parameter);
     } //foreach

     // look up each item from input to the report itself
     flag = "iterate_source_parms";
     foreach (Telerik.Reporting.ReportParameter sourceParameter in ReportParameters)
     {
      // the specified source parameter must exist in the report
      string key = sourceParameter.Name.ToUpper();
      if (!theDictionary.Keys.Contains(key))
      {
       throw new ApplicationException(
        string.Format(
         "Source parameter {0} does not exist in report parameters",
         sourceParameter.Name
        )
       );
      } //if
      Telerik.Reporting.ReportParameter reportParameter = theDictionary[key];

      // do simple type coercion
      flag = "decode_parm_types";
      Type typeReport = GetTypeFromReportType(reportParameter.Type);
      Type typeSource = GetTypeFromReportType(sourceParameter.Type);

      // shortcut
      if (typeReport == typeSource)
      {
       // set value explicitly
       reportParameter.Value = sourceParameter.Value;
       continue;
      } //if

      // simple type coercion (exception on failure)
      flag = "convert_" + sourceParameter.Name;
      object oParameterValue = Abr.CodeLibrary.DataAccess.DataObject.DbObject(
       typeReport, sourceParameter.Value, false
      );
      reportParameter.Value = oParameterValue;
     } //foreach
    } //next

    // set the report
    Report = theReport;
   }
   catch (Exception ex)
   {
    LH.error("Problem at ", flag, ": ", ex);
    NotifyError("Report Problem: " + ex.Message);
   } //try
  } //loadReport

  /// <summary>
  /// The stored report for display within this viewer
  /// </summary>
  public Telerik.Reporting.IReportDocument Report
  {
   get { return _report; }
   set { _report = value; if (_pageIsLoaded) setReport(); }
  } //Report

  /// <summary>
  /// For control via the ASCX properties, allow a report name to be specified.
  /// This name should be the class name of the report in the ArchG2.Reporting
  /// module. This property uses reflection to load the report for display by the control.
  /// </summary>
  public string ReportName
  {
   get { return _reportName; }
   set { _prevReportName = _reportName; _reportName = value; }
  } //ReportName

  /// <summary>
  /// Return reference to the stored report parameter actual list.
  /// Useful to access from code (use ReportParametersString from ASCX).
  /// </summary>
  public Telerik.Reporting.ReportParameterCollection ReportParameters
  {
   get { return _reportParameters; }
  } //ReportParameters

  /// <summary>
  /// Pass in report parameters as a string; parsed with ; (semicolon)
  /// as delimiter. Use Name=Value;[Name=Value;...] format.
  /// </summary>
  public string ReportParametersString
  {
   get { return _reportParametersString; }
   set
   {
    string flag = "";
    try
    {
     // anything to do?
     flag = "validate_parms";
     _reportParametersString = value;
     _reportParameters.Clear();
     if (string.IsNullOrEmpty(_reportParametersString)) return;

     // parse the report parameters
     flag = "parse_parms";
     string[] parms = _reportParametersString.Split(';');
     if (parms.Length == 0) return;

     // parse each parameter
     flag = "iter_parms";
     foreach (string parm in parms)
     {
      // sanity
      if (string.IsNullOrEmpty(parm)) continue;

      // validate
      int idxEqual = parm.IndexOf('=');
      if (idxEqual <= 0)
      {
       throw new ApplicationException(
        string.Format("Parameter {0} should be in format Name=Value", parm)
       );
      } //if

      // construct the parm
      string parmName = parm.Substring(0, idxEqual);
      string parmValue = parm.Substring(idxEqual + 1);
      Telerik.Reporting.ReportParameter reportParm = new Telerik.Reporting.ReportParameter(
       parmName, Telerik.Reporting.ReportParameterType.String, parmValue
      );
      _reportParameters.Add(reportParm);
     } //foreach

     // if we have already loaded the page,
    }
    catch (Exception ex)
    {
     LH.error("Problem at ", flag, ": ", ex);
     NotifyError("Report Problem: " + ex.Message);
    } //try
   } //set
  } //ParametersString

  /// <summary>
  /// Handle export status
  /// </summary>
  /// <param name="e"></param>
  protected override void OnInit(EventArgs e)
  {
   // create controls
   base.OnInit(e);
  }

  /// <summary>
  /// Auto-generated
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  protected void Page_Load(object sender, EventArgs e)
  {
   // indicate Page_Load has fired
   _pageIsLoaded = true;

   // check to see if we need to do a one-time load
   if (IsFirstTime)
   {
    if (Report != null)
    {
     // user set report explicitly; use that
     setReport();
    }
    else if (!string.IsNullOrEmpty(ReportName))
    {
     // report name set via ASCX; use that
     loadReport();
    } //if

    // only do this once
    SetFirstTime(false);
   } //if

   // set the height every time from hidden variable
   try
   {
    Unit unitExplicitHeight = Unit.Parse(hdnExplicitHeight.Value);
    if (unitExplicitHeight != Unit.Empty && unitExplicitHeight.Value > 0)
    {
     // safety
     if (unitExplicitHeight.Value < 100)
     {
      unitExplicitHeight = Unit.Parse("100px");
     } //if
     Height = unitExplicitHeight;
    } //if
   }
   catch
   {
   } //try
  }

  /// <summary>
  /// Put in our own control height (page height)
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  protected void rptvw_Init(object sender, EventArgs e)
  {
   string flag = "";
   try
   {
    // find the toolbar
    flag = "locate_toolbar";
    Control ctlToolbar = rptvw.FindControl("ReportToolbar");
    if (ctlToolbar == null) throw new ApplicationException("No toolbar; new Telerik version?");

    // this is reverse engineered from telerik; might work
    flag = "create_controls";
    Table tblHeight = new Table();
    tblHeight.ID = "PageHeight";
    tblHeight.CssClass = "ReportToolbarGroup";
    Abr.CodeLibrary.Utils.Global.MergeCssStyleAttributes(tblHeight.Attributes, "float:left;");
    tblHeight.CellPadding = 0;
    tblHeight.CellSpacing = 0;

    TableRow rowHeight = new TableRow();
    rowHeight.ID = "row";

    TableCell cellHeight = new TableCell();
    cellHeight.ID = "cell";

    Label lblHeight = new Label();
    lblHeight.ID = "lblHeight";
    lblHeight.AssociatedControlID = "txtHeight";
    lblHeight.Text = "Height: ";

    _txtHeight = new TextBox();
    _txtHeight.ID = "txtHeight";
    _txtHeight.Width = Unit.Parse("5em");

    LinkButton btnResize = new LinkButton();
    btnResize.ID = "btnResize";
    btnResize.Text = "Resize";
    btnResize.Click += new EventHandler(btnResize_Click);

    flag = "add_controls";
    cellHeight.Controls.Add(lblHeight);
    cellHeight.Controls.Add(_txtHeight);
    cellHeight.Controls.Add(btnResize);
    rowHeight.Cells.Add(cellHeight);
    tblHeight.Rows.Add(rowHeight);
    ctlToolbar.Controls.Add(tblHeight);
   }
   catch (Exception ex)
   {
    LH.error("Problem at ", flag, ": ", ex);
    NotifyError("Report: " + ex.Message);
   } //try
  }

  /// <summary>
  /// Used to capture explicit resize
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void btnResize_Click(object sender, EventArgs e)
  {
   hdnExplicitHeight.Value = _txtHeight.Text;
   Height = Unit.Parse(_txtHeight.Text);
  }
 } //TelerikReportViewer
} //namespace

 

 

 

 

 

 

3 Answers, 1 is accepted

Sort by
0
Shahzad
Top achievements
Rank 1
answered on 28 Dec 2011, 07:21 PM
Hi Manny,

I wana use Telerik Report dynamically on my web application. Actually the report name and parameter list would be load from database tables. So based on report and parameters list (if have) i need to load that particular report. Please guide me with some sample project that used earlier.

Thanks,

Shahzad
0
Peter
Telerik team
answered on 29 Dec 2011, 01:54 PM
Hi,

Telerik Reports are standard .NET types, thus they are part of assemblies. In order to load the reports you have to use reflection and instantiate the report based on the type as shown in the following code snippet:

Type reportType = Type.GetType(reportName);
IReportDocument report = (IReportDocument)Activator.CreateInstance(reportType);

Check out the attached sample project that illustrates the suggested approach.

All the best,
Peter
the Telerik team

Q3’11 of Telerik Reporting is available for download. Register for the What's New in Data Tools webinar to see what's new and get a chance to WIN A FREE LICENSE!

0
shahzad
Top achievements
Rank 1
answered on 29 Dec 2011, 07:20 PM
Hi Peter,

Thank you so much for getting reply with good example. That actually I was looking...

Thanks Again,

Shahzad.
Tags
General Discussions
Asked by
Manny
Top achievements
Rank 1
Answers by
Shahzad
Top achievements
Rank 1
Peter
Telerik team
shahzad
Top achievements
Rank 1
Share this question
or