Introduction
I am working on a project and have the task of evaluating different reporting engines which can be integrated
into or are well suited for our project.
I came across a freely provided reporting system by Microsoft. Though initially
it looks very difficult for me to understand,
when I delved further into it I liked it very much.
I searched the internet, relevant forums, and after an intensive study, I am publishing my findings here. This course is good for people who have
a basic knowledge of web applications,
class libraries and how to use them, and the target audience are beginners in
the reporting world.
Course for study
- Creating our Custom Data (Using List)
- Creating a Report using RDLC based on Custom Data
- Publishing Report
- Creating Secondary Custom Data (Using List)
- Creating Sub-Report and attaching to Main Report
- Adding Parameter to sub-report and passing data from Main Report
- Adding code to handle the Sub-Report
- Publish Report Again
Creating our Custom Data (Using List)
- Create a Web Application by selecting File->New->Project, select ASP.NET Web Application in Visual Studio 2010, and provide the name
CpReportCustomData.
- Similarly now add a class library which will act as our data source to keep the code simple and separate, say our class library name is CpReportCustomData.Data.
Remove the default class1.cs from the project.
- Now add a new class
Employee
in CpReportCustomData.Data, which would look something like this once complete:
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
See I have created a basic class, nothing fancy in it.
- Now add our
CustomDS
class which will act as an intermediary employee list and reports.
Our CustomDS
class would look something like this:
public class CustomDS
{
private static List <employee> _lstEmployee = null;
public static List <employee> GetAllEmployees()
{
if (_lstEmployee == null)
{
_lstEmployee = new List <employee> ();
_lstEmployee.Add( new Employee()
{
ID=1,
Name="Alok",
Age=30
});
_lstEmployee.Add(new Employee()
{
ID = 2,
Name = "Ashish",
Age = 30
});
_lstEmployee.Add(new Employee()
{
ID = 3,
Name = "Jasdeep",
Age = 30
});
_lstEmployee.Add(new Employee()
{
ID = 4,
Name = "Kamlesh",
Age = 31
});
}
return _lstEmployee;
}
}
- Compile and Build the class library.
- Add a Reference of your class library in
the web-application.
Creating a Report Using RDLC based on Custom Data
- Now your data setup is complete. Add a report, right click on the Web Application -> Add New Item -> Reporting -> Reporting Wizard, name it as rptAllEmployees.
You have two options here, either try to build the report yourself or take help of
the Report Wizard to create a skeleton based on DS.
- Once you add the report, the Dataset properties window would be open, choose Dataset name as DSALLEmployee and select Data Source as cpReportCustomData.Data and select CustomDS(GetAllEmployees) in Available Dataset.
Once you have done this setup,
the Fields list control would show you all the available Data fields.
Important: The Dataset name is very important, you have to provide this name every time you fill up data into the reports.
We will come to this point later.
- Now select all the available fields into the report and uncheck both Show Sub Report and Expand Group checkboxes.
- The basic framework would be ready and your report would look something like this:
Publishing Report
- Now in the default.aspx file, add Report viewer control from the tool box (name it rptViewer), since Report Viewer also requires
ScriptManger
, add that too.
- Now assign
rptViewer
our report (rptAllEmployees.rdlc) by selecting it in
the smart tag window.
- Now click on Choose data source and click on OK on the resultant dialog box.
It will automatically add the reference to our DS. If you see the code behind, our
Report Viewer HTML tag looks something like this:
<rsweb:ReportViewer ID="rptViewer" runat="server" Width="100%"
Font-Names="Verdana" Font-Size="8pt" InteractiveDeviceInfos="(Collection)"
WaitMessageFont-Names="Verdana" WaitMessageFont-Size="14pt">
<LocalReport ReportPath="rptAllEmployees.rdlc">
<DataSources>
<rsweb:ReportDataSource DataSourceId="ObjectDataSource1" Name="DSAllEmployee" />
</DataSources>
</LocalReport>
</rsweb:ReportViewer>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetAllEmployees" TypeName="CpReportCustomData.Data.CustomDS">
</asp:ObjectDataSource>
- Run and See the report.
Summary till now
- Created a custom Data class and returned it as a list of class objects using
a static function from the class library
- Created a report using report wizard and selected a class library as Data Source and
a static function as dataset
- Added a Report Viewer control on the Webpage, attached our report to it, and bound it to
a dataset to display data
Creating Secondary Custom Data (Using List)
- Add a new class
EmployeeFamily
in the CpReportCustomData.Data
class library, which would look something like this once complete.
Here you can consider the ID column as foreign key to the employee ‘ID’ field.
public class EmployeeFamily
{
public int ID { get; set; }
public String Name { get; set; }
public string Relation { get; set; }
}
- Similarly, add get function in the
CustomDS
class to which will return
a list of Employee Families. Once complete, it would look like this:
private static List<EmployeeFamily> _lstEmployeeFamily = null;
public static List<EmployeeFamily> GetAllEmployeeFamily()
{
if (_lstEmployeeFamily == null)
{
_lstEmployeeFamily = new List<EmployeeFamily>();
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 1,
Name = "AlokWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 1,
Name = "AlokDaughter",
Relation = "Daughter"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 2,
Name = "AshishWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 3,
Name = "JasdeepFather",
Relation = "Father"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 3,
Name = "JasdeepMother",
Relation = "Mother"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 4,
Name = "KamleshWife",
Relation = "Wife"
});
_lstEmployeeFamily.Add(new EmployeeFamily()
{
ID = 4,
Name = "KamleshDaughter",
Relation = "Daughter"
});
}
return _lstEmployeeFamily;
}
- Build the class library to update the changes done.
Creating a Sub-Report and attaching to the Main Report
- Follow the steps I used to create a report in Creating a Report using RDLC based on Custom Data,
and instead of
rptAllEmployees
, use name rptEmployeeFamily
and select
the Dataset Name as DSEmployeeFamily
, and instead of CustomDS(GetAllEmployees)
use
CustomDS(GetAllEmployeeFamily)
.
- After all settings, our report looks like this:
- Now Navigate to rptAllEmployees, right click on Age field and Insert Row -> Inside Group - Below.
- Merge cells of Name and Age columns in newly added row and add subreport from toolbox to it and name it rptEmpFamily.
Also for design purposes you can add a text box to the left as Family Details and provide your unique styling to it
- In rptEmpFamily Properties window, set report name as rptEmployeeFamily,
and now our report looks like this:
Adding Parameter to sub-report and passing data from Main Report
- Now we have already added our sub report to the main report, and we need to pass information about it to the sub report so we open Report Data view (View->Report Data)
of rptEmployeeFamily and right click on parameter to add the id parameter for
the report.
- Type name as EmpID, type as Integer, and allow to pass null values to it.
- Now in rptAllEmployees, open sub report properties, navigate to parameters, and add EmpID as Name and [ID] as its value and click
OK to save. This step ensures that
we are passing ID as parameter to sub report for every iteration of dataset in
the main report.
- Now your reports are complete, we have to add code in the main report viewer window to handle subrerport processing.
Adding code to handle Sub-Report
- Add Sub report processing event handler in
page_load
(you can add it anywhere, however it should
be before you fill data into the report).
if (!Page.IsPostBack)
{
rptViewer.LocalReport.SubreportProcessing +=
new Microsoft.Reporting.WebForms.SubreportProcessingEventHandler(LocalReport_SubreportProcessing);
}
- Now in
LocalReport_SubreportProcessing
method, add
the following code, the code explanation is in comments.
void LocalReport_SubreportProcessing(
object sender,
Microsoft.Reporting.WebForms.SubreportProcessingEventArgs e)
{
int iEmpID = Convert.ToInt32(e.Parameters[0].Values[0]);
e.DataSources.Clear();
var employeeFamily = CpReportCustomData.Data.CustomDS.GetAllEmployeeFamily()
.FindAll(element => element.ID == iEmpID);
e.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource()
{
Name = "DSEmployeeFamily",
Value = employeeFamily
});
}
- You can see we added the data source with name as DSEmployeeFamily, remember I told you it’s important!
Since using it, report recognizes what data to fill.
Publish Report again
- Nothing doing, just sit and relax, Visual Studio 2010 will build and run the report.
Points of Interest
- Report Viewer Control
- Creating RDLC Report
Special Thanks
- My parents, my wife and Parkhi!
History
- 08-Oct-2012: Started working
- 10-Oct-2012: Posted on CodeProject