简体   繁体   中英

Can i Bind List to SSRS report

i always bind dataset to report like this way

string exeFolder = Path.GetDirectoryName(Application.StartupPath);
string reportPath = Path.Combine(GetRootPath(), @"Report1.rdlc");
DataTable dt = GetDataSet();

List<ReportParameter> parameters = new List<ReportParameter>();
parameters.Add(new ReportParameter("ReportParameter1", "Hello"));

reportViewer1.Reset();
reportViewer1.ProcessingMode = ProcessingMode.Local;
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("dsJobs", dt));
reportViewer1.LocalReport.ReportPath = reportPath;
reportViewer1.LocalReport.SetParameters(parameters);
reportViewer1.RefreshReport();


so want to know can i bind list like

public class Person
{
public string Name1{get; set;}
public string Address{get; set;}
public string Email{get; set;}
}
List<Person> p = new List<Person>();
reportViewer1.LocalReport.DataSources.Add(new ReportDataSource(p));

please guide me. thanks

I have created a class which can help you mimic page-code-behind classes for the reports:

public abstract class ReportGenerator
{
    private readonly List<ReportParameter> _reportParameters;
    private readonly List<ReportDataSource> _reportDataSources;
    private readonly LocalReport _report;
    private readonly string _friendlyName;
    private IList<ReportGenerator> _subReports;
    private readonly string _repName;

    internal string ReportName
    {
        get { return _repName; }
    }

    public List<ReportDataSource> ReportDataSources
    {
        get { return _reportDataSources; }
    }

    public List<ReportParameter> ReportParameters
    {
        get { return _reportParameters; }
    }

    public abstract void SetParamsAndDataSources();

    protected ReportGenerator(string friendlyName, string reportName)
    {
        _friendlyName = friendlyName;
        _report = new LocalReport { ReportPath = string.Format("Reports/{0}.rdlc", reportName) };
        _repName = reportName;
        _reportParameters = new List<ReportParameter>();

        foreach (var paramIter in _report.GetParameters())
        {
            _reportParameters.Add(new ReportParameter(paramIter.Name));
        }

        _reportDataSources = new List<ReportDataSource>();
        foreach (var dsName in _report.GetDataSourceNames())
        {
            _reportDataSources.Add(new ReportDataSource { Name = dsName });
        }
    }

    private void report_SubreportProcessing(object sender, SubreportProcessingEventArgs e)
    {
        if(_subReports == null)
        {
            throw new ApplicationException(string.Format("Report '{0}' has subreport(s) which are not properly set up.", _repName));
        }

        var srLst = _subReports.Where(srIter => srIter.ReportName.Equals(e.ReportPath)).ToList();
        if (!srLst.Any())
        {
            return;
        }

        var srFound = srLst[0];

        foreach (var dsIter in srFound.ReportDataSources)
        {
            e.DataSources.Add(dsIter);
        }
    }

    public void RefreshReportViewer(out ReportViewer rvw)
    {
        InitReport();
        rvw = new ReportViewer();
        rvw.LocalReport.ReportPath = _report.ReportPath;
        rvw.LocalReport.SetParameters(ReportParameters);
        foreach (var dsIter in ReportDataSources)
        {
            rvw.LocalReport.DataSources.Add(dsIter);
        }
        rvw.LocalReport.SubreportProcessing += report_SubreportProcessing;
        rvw.LocalReport.Render("Word");
    }

    public byte[] GenerateReport(Formats reportFormat, out string mimeType, out string fileName)
    {
        SetParamsAndDataSources();

        ValidateReportParameters();
        ValidateReportDataSources();

        _report.SetParameters(_reportParameters);
        foreach (var dsIter in _reportDataSources)
        {
            _report.DataSources.Add(dsIter);
        }

        _report.SubreportProcessing += report_SubreportProcessing;

        Warning[] warnings;
        string[] streamIds;
        string encoding;
        string extension;

        fileName = string.Format("{0}_{1}.", _friendlyName, DateTime.Now.ToString("ddMMyyhhmmss"));

        var repExp = _report.Render(reportFormat.ToString("G"), null, out mimeType, out encoding, out extension, out streamIds, out warnings);
        fileName += extension;

        return repExp;
    }

    private void InitReport()
    {
        SetParamsAndDataSources();

        ValidateReportParameters();
        ValidateReportDataSources();

        _report.SetParameters(_reportParameters);
        foreach (var dsIter in _reportDataSources)
        {
            _report.DataSources.Add(dsIter);
        }
    }

    protected void SetSubReports(params ReportGenerator[] subReports)
    {
        _subReports = subReports.ToList();
    }

    private void ValidateReportParameters()
    {
        var paramsMetaData = _report.GetParameters();

        foreach (var paramIter in _reportParameters.Where(paramIter => paramIter.Values.Count == 0 && !paramsMetaData[paramIter.Name].AllowBlank))
        {
            throw new ApplicationException(string.Format(
                "Report {0}: Value not supplied for the parameter: {1}", _report.ReportPath, paramIter.Name));
        }
    }

    private void ValidateReportDataSources()
    {
        foreach (var dsIter in _reportDataSources.Where(paramIter => paramIter.Value == null))
        {
            throw new ApplicationException(string.Format("Report {0}: Value not supplied for the DataSource: {1}", _report.ReportPath, dsIter.Name));
        }
    }

    internal void SetReportParameterValue(string paramName, params string[] paramValues)
    {
        foreach (var paramIter in _reportParameters.Where(paramIter => paramIter.Name.Equals(paramName)))
        {
            paramIter.Values.AddRange(paramValues.ToArray());
            return;
        }
    }

    internal void SetDataSourceValue(string dataSourceName, object dataSourceValue)
    {
        foreach (var dsIter in _reportDataSources.Where(dsIter => dsIter.Name.Equals(dataSourceName)))
        {
            dsIter.Value = dataSourceValue;
            return;
        }
    }

    public enum Formats
    {
        PDF = 1,
        Excel,
        Word
    }
}

Sample code-behind for a report:

public class YourReport: ReportGenerator
{
    public string Parameter1 { get; set; }
    public string Parameter2 { get; set; }
    public string Parameter3 { get; set; }
    public string SubReportParameter1 { get; set; }
    public string SubReportParameter2 { get; set; }

    public List<SomeEntity> EntityList { get; set; }
    public List<SomeOtherEntity> SubReportEntityList { get; set; }

    private readonly CodeBehindClassForAnySubReport _anySubReport;

    public YourReport():base("ReportName", "ReportFileName")
    {
        _anySubReport = new YourReport();
        SetSubReports(_anySubReport);
    }

    public override void SetParamsAndDataSources()
    {
        SetReportParameterValue("Param1NameInReport", Parameter1);
        SetReportParameterValue("Param2NameInReport", Parameter2);
        SetReportParameterValue("Param3NameInReport", Parameter3);
        SetReportParameterValue("SubParam1NameInReport", SubReportParameter1);
        SetReportParameterValue("SubParam2NameInReport", SubReportParameter2);

        base.SetDataSourceValue("DataSourceNameInReport", EntityList);

        _anySubReport.EntityList = this.SubReportEntityList;
        //Call this only when subreport contains any datasource.
        //Parameters for subreports should be chained in the report design
        _anySubReport.SetParamsAndDataSources();
    }
}

Sample usage of the code-behind class in the front-end:

var repGen = new YourReport
                             {
                                 Parameter1 = someValue1,
                                 Parameter2 = someValue2,
                                 Parameter3 = someValue3,
                                 SubReportParameter1 = someValue4,
                                 SubReportParameter2 = someValue5,
                                 EntityList = someList1,
                                 SubReportEntityList = someList2
                             };

var repExp = repGen.GenerateReport(format, out mimeType, out fileName);

Response.Buffer = true;
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.BinaryWrite(repExp);
Response.Flush();

Some more notes to help:

What is Report Generator?

Report Generator is a library that serves like a code-behind for MS-Reports. It makes report export easy to use in the web layer.


How to use Report Generator?

For any new report, follow the steps below to mock a code-behind class:

  1. For each of the subreports in the report, ensure the following: (a) A report generator code-behind class is already coded using the same steps for the main report. (b) In the report designer the parameters of the main report are chained down to the sub-report parameters. And hence the sub-report parameters should be bubbled up and exposed as main report parameters.
  2. Create a new class for the main report deriving from the class 'ReportGenerator'.
  3. For each of the parameters in the main report (some of them bubbled up from the sub-reports as mentioned in 1b), add a new property to the new class.
  4. Create a readonly field for each of the subreport. The type of the field should be the code-behind class of the sub-report.
  5. Expose any sub-report datasource property as a main report property
  6. The constructor of the main report class should: (a) Call the base class constructor mentioning the physical name of the report as the method parameter. (b) Initialise all the sub-report fields, and add to the list of sub-reports by calling SetSubReports method.
  7. Override the method 'SetParamsAndDataSources'. This method should call: (a) SetReportParameterValue to set value(s) for each of the report parameters. Note that the values would be the corresponding class properties' values. (b) SetDataSourceValue to set the value for each of the report datasources. Note that the values would be the corresponding class properties' values. (c) SetParamsAndDataSources for each of the sub-report fields.

Follow the simple steps below to use the new class created, in the web layer:

  1. Create an instance of the new report generator class
  2. Assign values to the parameter & datasource properties
  3. Call GenerateReport method which returns the exported report as a byte array. Cascade this to the response as a file attachment.

What is the advantage of using Report Generator?

  1. It eliminates all the hard-coding of the parameter names and datasources in the web layer. Even though these are again hard-coded in the report generator classes, we get a control of what we are coding.
  2. The mocked-code-behind class is an object representation of the corresponding report, and hence makes the life easier for any object-oriented developer.
  3. All the complex functionalities of report generation is hidden inside ReportGenerator base class, and hence leaving only limited coding to be done for any new report.

Is the Report Generator base class reusable in any other projects?

Yes.


Any improvements can be made?

Yes, many. Few of them are: 1. Add a method to the ReportGenerator base class that can attach a report to a report viewer. 2. Currently the base class considers all the report parameters as of type 'string'. Can be modified to accommodate any type of parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM