Reporting Off CSLA.NET Business Objects

Reporting Off CSLA.NET Business Objects

Old forum URL: forums.lhotka.net/forums/t/2962.aspx


cmanders posted on Thursday, May 31, 2007

Hi All

I've been trying to create RDLC reports (ie. for ReportViewer), but my CSLA.NET based business objects do not appear in the data sources window.

From the book and from my investigations on the web it looks as though it should be possible.  I'm wondering if having put SP1 of VS is the issue why it doesn't work for me.  This is my first attempt at reporting off CSLA.NET based business objects - previously I had collections based off CollectionBase which worked fine (and still do).  In this project, if I create a collection class that inherits from CollectionBase then this appears in the data sources window.  If I change it to BindingList<T> (which the BusinessListBase inherits from) then the classes no longer appear in the data sources window.  Same project, same namespace, both supporting the IEnumerable interface.  Doesn't make sense to me - does anyone have any ideas?  I'm guessing there is no easy way, but I thought I might ask anyway.  I know I can use the ObjectAdaptor class to populate a dataset and report off that instead, but I don't really want to have to create datasets for each of my objects if I don't have to, incurring extra overhead and reducing the maintainability of my project.

I'm using SP1 of VS2005, with the reports in a ASP.NET Web Application project.  I'm using V2.1.4 of the CSLA.NET framework.

Any help would be much appreciated.

Regards

Chris Anderson

Q Johnson replied on Thursday, May 31, 2007

I haven't even done my first VS2005 / CSLA 2.x app yet.  But the experience I had with reports in 1.x may be useful for you. 

The interface that the report programs seemed to need to work with was IList, rather than IEnumerable.  And when I needed to do a quick report on an Editable Root Object (one that didn't support the IList interface), all I did was create an ArrayList and make my BO the only member.  I know it sounds incredibly trivial, but that worked perfectly.

So while you're waiting for another answer, you might give this a try in your circumstance.

Hope it helps.

tetranz replied on Thursday, May 31, 2007

I've become quite a fan of local rdlc reports driven from objects. I've built a few quite complex reports this way using objects built specially for the report. I think you've figured this out but for each "Table" in your report (often there is only one) you need to present a single collection. This means that you need to handle relationships in your objects.

I usually have one single ReadOnlyRoot which calls a stored procedure which often returns multiple result sets. I throw the data into collections of plain objects contained within the ROR. They don't need to be CSLA objects. My main "details" collection which is to be presented in a report table is usually a generic List(Of T). Related collections are usually added to a Dictionary(Of TKey, TValue). That way I can, for example, easily and efficiently provide CustomerName in my details table when my details are invoice line items. The CustomerName property of LineItem looks up related info by key quickly in the Dictionary. Sometimes I even use a Dictionary for my main details collection because I need to get back to the same object (report row) later in my DP_Fetch with data from another result set. Then I expose the .Values property of the dictionary. I connect to the objects with an object data source.

I really like the ability to massage the data in C# rather than in kludgy functions in the report or messy SQL. Of course any of my object properties can be used in the report to sort, group or filter on. All this is overkill if you just want to report on a simple table but its really not that difficult and I've managed to do complex things that would be a real PITA to do by traditional direct reporting from the db. It obviously has its (memory) limits for big reports with large amounts of data.

Cheers
Ross

pirithoos replied on Friday, June 01, 2007

Dear Chris,

I not sure if this is a solution, as I am not very familiar with RDLC reports.
But I faced assumeably the same problem with crystal-reports.
The BO were not shown as data source.
But when I created the reports in the same assembly where my BO were
stored CrystalReports did allow to bind to those BO's

Let me know if this helps.

Best Regards

Frank

tetranz replied on Friday, June 01, 2007

pirithoos:

I not sure if this is a solution, as I am not very familiar with RDLC reports.
But I faced assumeably the same problem with crystal-reports.
The BO were not shown as data source.
But when I created the reports in the same assembly where my BO were
stored CrystalReports did allow to bind to those BO's

rdlc is more flexible than this. You create an object datasource in the project / assembly where your rdlc file is but that datasource can use objects in any assembly.

The only location restriction I've noticed is when you embed the rdlc in the assembly and use the ReportViewer then the statement where you set the ReportEmbeddedResource needs to be in the same assembly as the rdlc. This means that the viewer and rdlc need to be in the same assembly or the rdlc assembly needs a reference to the viewer which implies that it also needs references to System.Windows.Forms or System.Web.

viewer.LocalReport.ReportEmbeddedResource = "<NameSpace>.MyReport.rdlc"

Ross

cmanders replied on Monday, June 04, 2007

Thanks for your replies guys.  Unfortunately none of them help.  The business objects I'm trying to report off are based upon IList.  I can copy the data into new non-csla objects (those objects do show up), but I'd rather avoid double handling the data if I can - it just seems messier and more maintenance to do it that way.  My business objects are based in the same assembly as the reports also, but they just don't show up.

Thanks for your help anyway - looks like I'll just have to work around it by copying the data to datasets and building my reports off those.

Chris Anderson

RSB replied on Monday, June 04, 2007

Hi

I am tyring to serialize a business object using XML serializer.  My objective it to generalize the ToXML( ) method for any BO.  I pass in the object to the below code, the error I get is as follows:

There was an error reflecting type of the business object type.


Cannot serialize member 'Csla.Core.BusinessBase.BrokenRulesCollection' of type 'Csla.Validation.BrokenRulesCollection', see inner exception for more details.

Csla.Validation.BrokenRule cannot be serialized because it does not have a parameterless constructor.

My question is:  How to ignore the Csla.Validation.BrokenRule member? I can use XMLIgnore attribute? 

Or any other suggestions to overcome this error?

Code as follows:

using System.IO;

using System.Xml.Serialization;

using System.Xml;

using System.Text;

//calling code

//set the object and its properties which need to be converted to XML document

string x = SerializeObject(CSLAobject);

 

//method used for serializing

public String SerializeObject(Object pObject)

{

try

{

String XmlizedString = null;

MemoryStream memoryStream = new MemoryStream();

XmlSerializer xs = new XmlSerializer(typeof(CSLAObject));

XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

xs.Serialize(xmlTextWriter, pObject);

memoryStream = (MemoryStream)xmlTextWriter.BaseStream;

XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());

return XmlizedString;

}

catch (Exception e)

{

System.Console.WriteLine(e);

return null;

}

}

/// <summary>

/// To convert a Byte Array of Unicode values (UTF-8 encoded) to a complete String.

/// </summary>

/// <param name="characters">Unicode Byte Array to be converted to String</param>

/// <returns>String converted from Unicode Byte Array</returns>

private String UTF8ByteArrayToString(Byte[] characters)

{

UTF8Encoding encoding = new UTF8Encoding();

String constructedString = encoding.GetString(characters);

return (constructedString);

}

Cslah replied on Monday, June 04, 2007

We're using rdlc files for all of our reports on top of the Csla 2.1.4 framework. A great resource for reporting is www.gotreportviewer.com. They've got tons of samples that will get you up and going.

I will report one 'gotcha' with the reportviewer control that caused me to lose lots of hair. You won't see the Reports menu in the designer unless you click on the report. This might have been fixed in VS SP1. Also, for sub-report processing you'll need to trap an event that's tossed when the subreport is being loaded. Within the event you load (if you need) your BO & bind it there.

We bind directly to the objects, no problem, no changes needed. IList is all you need. I'm using winforms, not ASP.net, but it should be the same. What you do is create a data source for your object, same as what you'll do with databinding. Use that same datasource, create an rdlc file and just drag/drop the items you want onto the report. The datasource will be hooked up automatically, or you can click on Reports menu-Data Sources to see them. Then, you have to load the datasource similar to databinding. For us, this is done within the winform that contains the reportviewer control, yours will probably be the same in the ASP page:

' Reset report viewer (for when user clicks refresh button)
rptViewer.Reset()

' Set processing to local
rptViewer.ProcessingMode = ProcessingMode.Local

' Put settings in report mode, this controls formatting of names
My.Settings.ReportMode = True

' Load your Csla collection or list object 
Dim
custs As
YourCollection
custs = YourCollection.GetYourCollection()

' Point viewer at report (we store these in a \reports\ folder)
rptViewer.LocalReport.ReportPath = My.Application.Info.DirectoryPath & "\Reports\YourReport.rdlc"

' Load the datasource (this is the name from the report d.s. properties)
rptViewer.LocalReport.DataSources.Add(New ReportDataSource("Library_YourCollection", custs))

 

Copyright (c) Marimer LLC