none
Reporting Control Needs Work RRS feed

  • Question

  • I've a sincere appreciation for Microsoft's work on these Visual Studio Report Controls:

    1: I like the idea of it being free.

    2: I like the flexibility of being able to create report layouts on the fly (thanks to XML definition)

    3: I like many of the features built into the controls (.PDF exports, etc)

     

    That said, there are some very frustrating problems with these controls that must be fixed:

    1: I've a 3.0GHz Dell with 1GB of RAM running XP and just opening up an .rdlc file in my VS2005 environment will bog my system down considerably. 

    2: Merely closing a .rdlc file (design view) will often lock up my machine.  I have to carefully close 'em one at a time waiting for each distinct file to close - doing a 'close all' if several are open means almost certain lockups.

    3: I use object orientated design but I hate the world of drag and drop.  I don't like little xsd files being created all over the place and I hate the idea of connection strings being embedded in little secret locations all over the place every time I drag and drop something.  I work in an environment that must be secured and all connection strings must be encrypted.

     

    Please improve in the following ways:

    1: Stability.

    2: Use of system resources just to open or close in a designer must be reduced significantly.

    3: Allow the reports to be object data source agnostic - I don't want the environment doing all kinds of magic in the background.  Allow me to attach an object to a local report and define what data fields (properties on the object) I want the report to grab.  If I make a mistake and the property doesn't exist on the datasource, ignore it.

     

    As it stands, I have to manually edit the XML (which it is cool you can do this) because I don't want these damn xsd files, datasets, and dozens of other trinkets all over my project just to connect to an object data source.

     

    Thanks for listening.

    I WANT to use this product but so far its been frustrating.

    The results are nice once you plow through the system crashes and learn how to avoid connection strings scattered all over the place.

     

    EDIT TO ADD: I work in an environment where there is mounting pressure to convert to Java.   The more slick MS tools I can pull out of my hat (for free) the better off I'll be.  This reporting tool could be a big selling point for someone in my position.

     

    =)

    Wednesday, March 5, 2008 4:24 PM

Answers

  • It actually does what your asking it to do, you just need to step back and think about how your handling it.   In reality, the only thing your solution has to have in order to display a report is the report viewer itself.  you don't need those datasets or any of those other things stuck in your project.     

     

    In describing what you want, you've almost described exactly how it designed to work, you just need to type the code.

     

    let me try to give an example.

     

    I Have a project, that has one page with a reportviewer control on it.   This page is designed to handle displaying over 100 different reports.

    Code Snippet

     

    DataSet ReportDataSet = new DataSet();

    protected void Page_Load(object sender, EventArgs e)

    {

    //Code to fill ReportDataSet

    An 

    //a method that handles the report template based on the dataset structure

    LoadReportDefinition(ReportDataSet);

     

    ReportViewer1.LocalReport.DataSources.Clear();

    //attach our returned datatable as a reportdatasource

     

    ReportDataSource customReportData = new ReportDataSource();

     

     

     

    customReportData.Name = "ReportDataset_ReportData1";

    customReportData.Value = ReportDataSet.Tables[0];

     

     

    ReportViewer1.LocalReport.DataSources.Add(customReportData);

    ReportViewer1.LocalReport.Refresh();

    }

     

    private void LoadReportDefinition(DataSet  reportTemplate)

    {

    //loads the correct RDLC template for the dataset passed in

     

    }

     

     

    this isn't my exact code, as I'm not aloud to provide that, but it's a general summary of what's happening.  This basic structure handles loading over 100 different reports to a single viewer.   And my project contains nothing more then the viewer, and the page which contains it.

     

    The datasource in this case is always a dataset, and in the example I only load one table, but that was just for keeping the example simple.


    In all 100 reports, the Datasource name is the same, since DatasourceName really isn't important at all, untill you start loading more then one table, or more then one datasource, in which case I would still keep it very anonymous in using

     

    ReportDataset_ReportData1

    ReportDataset_ReportData2

     

     

     

     

    None the less, all the work happens in the Loading of the report definition, and since your loading XML, the sky is the limit in regards to what you load.    If you just want to hardcode 100 different .RDLC files...go for it.

     

    If you want to use just one .RDLC file, and modify it to match your dataset prior to giving it to the report viewer, go for it.  I recommend using XSLT to simplify it.

     

     

    The reality is, you don't need all the extra stuff if you don't want it, the question is just a matter of deciding how dynamic you want/need everything to be?
    Wednesday, March 5, 2008 8:36 PM
  •  

    Blast2Hell,

     

    I've fixed my problems and I'm up and running.

    As it turns out I had several issues.

     

    1: I had an older project type which greatly complicated things.  I'll use the ASP.NET WEB APPLICATION from now on because it seems to match the behavior that we find in the documentation.   I can add a class library project to the solution and the whole thing works as advertised.

     

    2: If you want your objects to appear as data sources in the 'Website Data Sources' window and those objects are in a project of type "Class Library" you need to rebuild the solution and then refresh the data sources panel (see the little refresh icon in the panel).

     

    3: For all the noobs out there like me: You can only see the 'Website Data Sources' window when you've got a report open in designer mode. 

     

    4: If the object that you are trying to use as a datasource has only a private constructor (this is done to force the use of a shared factory method) the object won't show.  (I believe this is the case.... I've not checked this thoroughly)

     

    5: You have to return a List(of [object type]) - that is, provide a 'Select Method' per the ReportViewer documentation in order for the object to show as a data source.

     

    Anyways, after piling through all that the silly thing works now.

     

    -MadGerbil

    Wednesday, March 12, 2008 9:00 PM

All replies

  •  

    Item 3 in regards to your security concerns is already a reality.  The report doesn't have to be bound to a dataset in the designer....although it make it easy to use on for designing the layout of the report, you can drop it after that and just attach your datasource to the report programatically..  And as long as your datasource has the right name, it will ignore fields that it doesn't need.
    Wednesday, March 5, 2008 4:31 PM
  •  

    I want it to ignore fields it doesn't find.

    Check the object for the required field and if it doesn't exist, ignore.

     

    The problem with this reporting control is that it is trying to do TOO MUCH for the developer and in the process one ends up with all kinds of problems when simply trying to use the control programatically (without drag-n-drop & the subsequent 500 little files that creates - files scattered about with password information in them).

     

    Unless I'm mistaken I have to go into the Report Data Sources popup (Report --> Datasource) and select from project data sources.  It then assigns a name to the expected datasource - a project datasource - which is what I want to avoid because when I create a project data source I get all kinds of extra files that compromise security.  The UI doesn't allow me to type in my own name for the datasource.

     

    So when I get around to adding my object datasource programmatically I have to use the name assigned by the UI and then I have to go delete all those extra stupid files.

     

    ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("[use the name assigned by the UI]", col))

     

    I've found that when I want to change the definition for my report - let's say for example, my object had a new property added and I want that to show on the report - that it is easier just to open the XML file and hand edit the XML to add the new field than try and use the designer.

     

    The better approach would be to allow me to drop whatever datasources I want to (objects) into the local report's datasources collection and assign those objects any name I want and then be allowed to reference those on my report thusly:

     

    [datasourceName].[fieldName].value

     

    Now I know that I wouldn't have the environment checking to make sure the field actually exists in the object (or dataset) like it does with the current implementation but gosh, those kinds of errors take all of 3 minutes to fix - a whole lot less time than I spend trying to delete dozens of extra files and goobering around with UI created report data sources that I don't require.

     

    If I wanted all that extra stuff I'd program in Access.

     

    Again, it is a fine first stab at a reporting control but so far it isn't nearly as easy to use as DataDynamics ActiveReports.

    Make it ease like that!

     

     

     

     

     

    Wednesday, March 5, 2008 8:08 PM
  • It actually does what your asking it to do, you just need to step back and think about how your handling it.   In reality, the only thing your solution has to have in order to display a report is the report viewer itself.  you don't need those datasets or any of those other things stuck in your project.     

     

    In describing what you want, you've almost described exactly how it designed to work, you just need to type the code.

     

    let me try to give an example.

     

    I Have a project, that has one page with a reportviewer control on it.   This page is designed to handle displaying over 100 different reports.

    Code Snippet

     

    DataSet ReportDataSet = new DataSet();

    protected void Page_Load(object sender, EventArgs e)

    {

    //Code to fill ReportDataSet

    An 

    //a method that handles the report template based on the dataset structure

    LoadReportDefinition(ReportDataSet);

     

    ReportViewer1.LocalReport.DataSources.Clear();

    //attach our returned datatable as a reportdatasource

     

    ReportDataSource customReportData = new ReportDataSource();

     

     

     

    customReportData.Name = "ReportDataset_ReportData1";

    customReportData.Value = ReportDataSet.Tables[0];

     

     

    ReportViewer1.LocalReport.DataSources.Add(customReportData);

    ReportViewer1.LocalReport.Refresh();

    }

     

    private void LoadReportDefinition(DataSet  reportTemplate)

    {

    //loads the correct RDLC template for the dataset passed in

     

    }

     

     

    this isn't my exact code, as I'm not aloud to provide that, but it's a general summary of what's happening.  This basic structure handles loading over 100 different reports to a single viewer.   And my project contains nothing more then the viewer, and the page which contains it.

     

    The datasource in this case is always a dataset, and in the example I only load one table, but that was just for keeping the example simple.


    In all 100 reports, the Datasource name is the same, since DatasourceName really isn't important at all, untill you start loading more then one table, or more then one datasource, in which case I would still keep it very anonymous in using

     

    ReportDataset_ReportData1

    ReportDataset_ReportData2

     

     

     

     

    None the less, all the work happens in the Loading of the report definition, and since your loading XML, the sky is the limit in regards to what you load.    If you just want to hardcode 100 different .RDLC files...go for it.

     

    If you want to use just one .RDLC file, and modify it to match your dataset prior to giving it to the report viewer, go for it.  I recommend using XSLT to simplify it.

     

     

    The reality is, you don't need all the extra stuff if you don't want it, the question is just a matter of deciding how dynamic you want/need everything to be?
    Wednesday, March 5, 2008 8:36 PM
  • Blast2Hell,

    Thank you for the answer.

    Does that technique work with the report value being set to an instance of an object?

    Or does it have to be a datatable?

     

    Wednesday, March 5, 2008 9:56 PM
  • I personally haven't used an object as a datasource yet, but I know you can do it.  In fact someone else had a thread talking about how they were using an object, but I'm not able to find it at the moment.

    Wednesday, March 5, 2008 9:59 PM
  •  

    I've used objects as datasources.

    I'm hoping I can now do it in the same way Blast2Hell attaches tables.

    I don't want to have to mess around with xsd files and all that noise.

     

    If I use objects as the data source then the connection string can be encrypted and buried in the object.

    I like that extra level of security.

    Thursday, March 6, 2008 8:43 PM
  • In the link provided above for object data sources the  following phrase is not accurate:

    "There is no separate step to make the class appear in the Website Data Sources window. All classes that qualify as object data sources automatically appear in the Website Data Sources window. In order for a class to qualify as an object data source, there should be a "Select method" that returns a collection of objects of that class."

     

    While that is true for a WebSite I'm not using a Web Site project, I'm using a ASP.NET WEB APPLICATION (VS2005)which doesn't automagically create an App_Code folder for you upon creation of a class and does not automagically create the "web data source" for objects that meet the aforementioned criteria.

     

    I'd love to see an example of an object being dynamically attached to a local report when that object is located outside of the App_Code folder or in another project entirely (in the same solution).

    Monday, March 10, 2008 4:56 PM
  • I think I've found part of my problem.

    I'm using an application and the objects are in a different project than the reports.

    I'd like to know how to use those objects as object data sources for my reports.

    Monday, March 10, 2008 6:06 PM
  •  

    Okay, here is the entire scenario:

     

    I've an ASP.NET WEB APPLICATION which contains two projects.

    The first project is an ASP.NET web site and the second is a VB Project.

    The VB Project contains all of my business objects.

     

    My report (rdlc) files are located in the web site and the objects I wish to bind to are contained in the VB project.

     

    Somehow I need to connect an object data source to my local report without creating all kinds of extra files (.xsd, datasets, xml files, and stashes of connection strings, etc.).  

     

    First Attempt: (in sub report processing):

     

     

    Code Snippet

    Select Case e.ReportPath

    Case "RV_subChangeLogs"

    Dim ds As New ReportDataSource

    ds.Name = "UILog"  'UILog also the object type name

    ds.Value = obj.Logs.GetUILogs  'A List(of UILog) items

    e.DataSources.Add(ds)

    End Select

     

     
    So I've added a ReportDataSource to the sub report but I don't know how to reference the datasource in the actual report designer.   I naturally thought I'd add a new object datasource to the web site but it only allows me to add database web sources - the ability to add an object data source isn't coming up.
     
    I'm totally baffled as to why this is so difficult. 
    Monday, March 10, 2008 6:39 PM
  • I also tried this:

     

    Dim ods As New ObjectDataSource

    ods.TypeName = "RV.Library.UILogs"

    ods.SelectMethod = "GetUILogs"

    e.DataSources.Add(New ReportDataSource("UILogs", ods))

     

    ...but then when I view the .rdlc file in the designer I don't know how to reference the fields on the report.

    Monday, March 10, 2008 7:12 PM
  •  

    Just to try and figure this thing out I've created a brand new WEB APPLICATION and I've created two objects (singleton and collection).  When those classes were created it didn't ask to put them into a App_Code file and they don't show up in the Website Data Sources pane.   Is there any reason why an ASP.NET WEB APPLICATION should work any differently than a web site in regards to data sources for .rdlc files?
    Monday, March 10, 2008 8:57 PM
  • Okay, I've identified a couple of problems that I've now fixed.

    I'm not there yet, but at least my objects, which are contained in a class library, are now appearing in the website data sources tab.

     

    1: My project type was an older project type.  I thought I was using an ASP.NET WEB APPLICATION but I think I had an older version of that project type.  I've created a new one and I'm adding my files/references to it and it seems to be working.  May be a patch issue (pre vs. post) or something - doesn't matter to me either way.

     

    2: Objects that have private constructors will not show in the website datasources window.  I use factory methods to create all my objects - apparently you must have a public constructor for these objects to work as a datasource.

     

     

    Tuesday, March 11, 2008 6:35 PM
  • I'm sorry I don't have anything further to offer on what you're trying to do.  Like I said, i haven't messed with Object data sources very much.   But please keep posting your findings, as it's very interesting info in case I decide to do it later.

     

    If you bump into something that I can shed some light on, i'll surely try.

    Wednesday, March 12, 2008 7:09 PM
  •  

    Blast2Hell,

     

    I've fixed my problems and I'm up and running.

    As it turns out I had several issues.

     

    1: I had an older project type which greatly complicated things.  I'll use the ASP.NET WEB APPLICATION from now on because it seems to match the behavior that we find in the documentation.   I can add a class library project to the solution and the whole thing works as advertised.

     

    2: If you want your objects to appear as data sources in the 'Website Data Sources' window and those objects are in a project of type "Class Library" you need to rebuild the solution and then refresh the data sources panel (see the little refresh icon in the panel).

     

    3: For all the noobs out there like me: You can only see the 'Website Data Sources' window when you've got a report open in designer mode. 

     

    4: If the object that you are trying to use as a datasource has only a private constructor (this is done to force the use of a shared factory method) the object won't show.  (I believe this is the case.... I've not checked this thoroughly)

     

    5: You have to return a List(of [object type]) - that is, provide a 'Select Method' per the ReportViewer documentation in order for the object to show as a data source.

     

    Anyways, after piling through all that the silly thing works now.

     

    -MadGerbil

    Wednesday, March 12, 2008 9:00 PM
  •  

    excellent information, glad you got it worked out.  I'll keep #5 in mind if ever I use objects.
    Thursday, March 13, 2008 1:26 PM
  • Hi Blast2Hell

     

    I've been looking at your code and I think it makes sense but...

     

    The loadreportdefinition function, what does that do? Does it load the report.rdlc file passing in any parameters etc and if so do you have a bit of code that you can show me to load a report.

     

    Since you are passing it a dataset I suppose you're only passing it the data you want to display. How do you display it in the report since they are not linked until you load them? I can't see how you can place things on the report when the report doesn't know what data it's getting.

     

    These are probably dull questions but they are really bugging me.

     

    Cheers

    Jon

    Thursday, March 20, 2008 5:27 PM
  •  

    ReportViewer1.LocalReport.LoadReportDefinition

     

     

    This basically accepts a stream, the stream of course has to be in a valid format that the report viewer can read.  It's used when you don't have a file path to give the report viewer.  For instance, say you retrieve your report templates from a data portal of some sort, and it just spits everything out as a byte array.   In that case you would just hand the .rdlc file to the report viewer as a stream, since there is no physical path to the file for it to reference/access.

     

    This only loads the report to be used,  the report itself knows what data it needs,  Not the report viewer.  The report viewer merely takes the  .rdlc file and does what it's told.   So if your .rdlc file says it needs 4 datasources, then the reportviewer will read that, and expect them to be provided, otherwise it will give the error saying you didn't provide them.

     

     

     

     

    The report, and the data are actually linked at design time essentially.  When designing a report, it will store the name associated with every bit of data used in it.  If you open the report in an xml viewer, you'll see it's stored the name of every datafield, along with other pertinent information. 

     

    So the raw concept is to setup your .rdlc at design time with all the data it might need.  And then at runtime hand your reportviewer the datasources that match the datasources that were stored in the report.

     

    Hope this makes sense, if not, feel free to ask further questions.

    Thursday, March 20, 2008 8:19 PM
  • Hi All,

    Even I ran into the same problem. I have the report application and I am adding 2 classes for creating my own strongly typed dataset. After adding the classes I build the application and then add a report. But I dont see my datasource. Please help me. The classes which I added:

    Public Class Product

    Private m_name As String

    Private m_price As Integer

    Public Sub New(ByVal name As String, ByVal price As Integer)

    m_name = name

    m_price = price

    End Sub

    Public ReadOnly Property Name() As String

    Get

    Return m_name

    End Get

    End Property

    Public ReadOnly Property Price() As Integer

    Get

    Return m_price

    End Get

    End Property

    End Class



    Public Class Merchant

    Private m_products As List(Of Product)

    Public Sub New()

    m_products = New List(Of Product)()

    m_products.Add(New Product("Pen", 25))

    m_products.Add(New Product("Pencil", 30))

    m_products.Add(New Product("Notebook", 15))

    End Sub

    Public Function GetProducts() As List(Of Product)

    Return m_products

    End Function

    End Class

    Wednesday, December 10, 2008 7:18 PM