Converting Objects to XML

Converting Objects to XML

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


MadGerbil posted on Tuesday, January 09, 2007

I'm putting some error trapping into my web pages and I think a helpful thing to record would be an XML version of the object to the database so I can get an idea of what the user was working with when the web page erred.   I figure the best way to store it would be as XML.

So I'd like a way to cause an object and all of it's children/collections to be converted to XML so it may be saved in a database as a text field.  This way I can examine the object in instances of hard to crack bugs.

I suppose I could just serialize it out?

Thoughts?

Suggestions?

 

snesbitt replied on Tuesday, January 09, 2007

The WCF DataContractSerializer does a great job of serializing objects that contain collections and lists.  The resulting XML is very clean and you have full control to re-order and re-name the resulting XML elements.  I've used this serializer with good results in my last project when I needed to serialize an object that contained collections - even though I was not using any other WCF functionality.  The downside is that you need to go back and define your objects as DataContracts and all properties you want serialized as DataMembers (this new serializer uses an opt-in policy unlike the XmlSerializer).  This may sound like a big task but it really is quite straight-forward - provided you aren't dealing with 100's of objects and properties of course.  Your objects can continue to be used in the same way after they've been decorated it with the WCF attributes.

If you havent delved into WCF yet and you want any further help, just let me know.

Best of luck,

Steve

 

RSB replied on Monday, June 04, 2007

I have this problem serializing CSLA BO into XML. I use XMLSerializer, the error as follows:

There was an error reflecting type 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.

How to ignore the Csla.Validation.BrokenRule member in XML serialization?

Also, I would like to know what you had done in the above case?

Thanks,
RSB

 

William replied on Tuesday, June 05, 2007

CSLA comes with ObjectAdapter implementation, which converts your object or collection into a DataSet/DataTable. This might be a quick solution for you; or, it serves as a base to start your own XML serialization.

Regards,
William

Jimbo replied on Tuesday, June 05, 2007

ObjectAdaptor has its problems - which Rocky admits to (see recent posts) . Currently it can't deal with Nullables, which is causing me an issue. Also it will only produce a DataTable of the parent object or collection public properties (including IsDirty, IsValid, and BrokenRules etc.). rather than a DataSet containing all child objects.

Jimbo

RSB replied on Tuesday, June 05, 2007

Oh, this is the problem I am facing now. Any other suggestions?

Thanks,
RSB

RSB replied on Tuesday, June 05, 2007

William,

Thank you, This worked. But How do I get the XML for the child object which is a list. For example, A business object has a property which is a childList. How do I get the XML for this one along with the parent? I am getting the Parent properties.

<XML-Parent>

   <ChildList>

     <Child>

        </Child>

  </ChildList>

<XML-Parent>

Thank you
RSB

William replied on Tuesday, June 05, 2007

I think ObjectAdapter does not automatically work with child objects. However,  you can still use ObjectAdapter and follow the patterns of DataSet, where your BO exposes a GetXml() method. Internal to this method, use ObjectAdapter on the object as well as all child objects to get DataSet presentation then to XML.

Regards,
William

xal replied on Tuesday, June 05, 2007

You can implement IXmlSerializable  in your classes and do the serialization by hand. It isn't awfully hard, but it's not as straightforward as using the xmlserializer without implementing that ;).

I wonder why doesn't Rocky just mark those properties with an XmlIgnore attribute so that people can serialize their objects to xml if they want to. Then it's up to you if you want to "break the model" and have a public parameterless constructor, being aware of the limitations of the xml serializer, of course (public r/w props only).

Then again, if we're talking about breaking the model, you may as well mark those conflicting properties with XmlIgnore in your own version of csla and that's it.


Andrés

RSB replied on Wednesday, June 06, 2007

Thank you folks!

I have started writing my own serializer. I am using the reflection and xml namespaces.  I am passing in the object, getting its all properties and the propertyinfo using PropertyInfo class. (FieldInfo class can also be used).  My problem is, if there is a child list in the parent object, I have to get the childlist object, cast it to the BusinessListBase. This is the place, I am stuck!!I am not sure on how to do this?? Code as below, any help appreciated !!

public string Serialize( object o, Type t)

{

//string str = pi.GetValue(pi,0).ToString();

// start writing!

PropertyInfo[] pi = t.GetProperties();

XmlTextWriter writer = new XmlTextWriter("c:/test.xml", System.Text.Encoding.UTF8);

writer.WriteStartDocument();

writer.WriteStartElement("root");

foreach (PropertyInfo p in pi)

{

if (p.PropertyType.BaseType.Name.Equals("BusinessListBase`2"))

{

 

string s = p.Name;      //property Name

object ox = p.GetValue(o,null);     // property Value

if (ox.GetType() == typeof(BusinessListBase))      //if child list object

{

Type ti = ox.GetType();

// how to get the child object value ??

//recursively call Serialize
// Serialize(object childObject, type BusinessListBase)

}

}

else // normal property

{

 object op = p.GetValue(o, null);

 writer.WriteElementString(p.Name, op.ToString());

}

}

writer.WriteEndElement();

writer.WriteEndDocument();

writer.ToString();

writer.Close();

return "";

}

 

Thanks,
RSB

snesbitt replied on Wednesday, June 06, 2007

RSB,

I think this will be close to what you need.

Hope this helps

Steve

 

// ... extract from above ...

if (ox.GetType() == typeof(BusinessListBase))      //if child list object

{

   foreach (object childObject in (IBindingList)p.GetValue(ox, null))

   {

      Serialize(childObject, typeof(childObject));

   }

}

RSB replied on Wednesday, June 06, 2007

Thank you Steve,

I get error in the place where I typecast the object as in (IBindingList)p.GetValue(ox, null)).  It says object target not matched, target exception thrown.  I used IExtendedBindingList ..

Thank you !
RSB

ajj3085 replied on Tuesday, June 05, 2007

YOu can't use the XmlSerializer for Csla based objects.  That requires that all properties have get AND set methods, and that you have a public, parameterless constructor.  Both of those things go against the grain of Csla design. 

If the ObjectAdapter doesn't work for you, you may have to come up with a similar class.  It sounds like others say you can use the new serializer in WCF to get xml, that's probably the best way to go.  You need to avoid binary formats because if you update your BO assembly, you may lose the ability to read the data into an object again.

snesbitt replied on Tuesday, June 05, 2007

The WCF serializer will have the same requirements as XmlSerializer in that all props need getters and setters, public parameterless constructor etc.  So that wont help you I'm afriad.  My original post about the WCF serializer was misleading in that I havent used it with CSLA objects - just home grown objects. Sorry.

ajj3085 replied on Tuesday, June 05, 2007

Hmm.. I didn't think the WCF serializer had that limitation, especially since Rocky enables us to use it for N-level undo... perhaps I'm thinking of something else in WCF though.

SonOfPirate replied on Tuesday, June 05, 2007

The built-in serializer (System.Xml.Serialization.XmlSerializer) provided at part of the .NET Framework has the following well-documentation short-comings:

I am not familiar with the WCF Serializer, yet, and had to develop my own custom serializer a couple of years ago to get around these limitations because it was the only way to support it with Csla.  With it, what you are asking to do is as sinple as calling the ToXML() method on my BO.  Unfortunately, the code is proprietary to the employer but I can tell you that it isn't that hard to do - just takes time.

HTH

 

 

RockfordLhotka replied on Thursday, June 07, 2007

ajj3085:
Hmm.. I didn't think the WCF serializer had that limitation, especially since Rocky enables us to use it for N-level undo... perhaps I'm thinking of something else in WCF though.

The WCF DataContractSerializer has many of the limitations of the XmlSerializer. However, the NetDataContractSerializer is what I use in CSLA, because it works the same as the BinaryFormatter, but produces and consumes XML instead of a binary blob.

It is important to realize, however, that serializing an object graph in a way that you can put it back together as an exact clone requires that the XML contain more data than just the simple <name>value</name> content... If you look at the output from DCS you'll see a simple format, which is why it isn't useful to CSLA - because it can not create an exact clone. The NDCS produces slightly more complex XML - but it can create an exact clone.

I don't recommend the SoapFormatter, because it is deprecated. That, and it produces really complex XML using a now-defunct serialization scheme from the SOAP spec.

But what you might consider is writing your own. If all you need to do is serialization - NOT deserialization - then it is really quite easy to use reflection to create your own serializer. You can model it after the code in UndableBase - or look back at CSLA .NET 1.x, which had (on and off) an ObjectDumper (or something) method that would serialize an object graph into text for debugging.

Bowman74 replied on Thursday, June 07, 2007

I don't know Rocky, that seems like a lot of work for not a lot of benefit.  As I understand the situation all he wants is to write out the current state of his object when an error occurs on his website to help with debugging.

Sure the SOAPFormatter my be depreciated and the contents convoluted, but does that really matter?  You can read through it to see the memory variables with not too much trouble or if you are really stuck just reconstitute the object with almost no code.  If (and this may never happen) at a later date he upgrades to some later version of .Net that doesn't include the SOAPFormatter then he can rewrite his centralized error handling scheme at that time.  It's not like he is going to care that the format of his serialized objects for helping with debugging has changed. 

He may never rewrite his application to use a later version of .Net or if he does custom serialization that may also need to be rewritten.  If he is smart and has a centralized handler for writing out his error information its not like he will be rewriting much and when whatever version of .Net he is switching to comes out he may have a better understanding of the best way of serializing them for that version.  Just write a few simple lines of code with the SOAPFormatter and be done with it and get back to the real business problems.  IMHO, of course.

Thanks,

Kevin

ajj3085 replied on Thursday, June 07, 2007

RockfordLhotka:
The WCF DataContractSerializer has many of the limitations of the XmlSerializer. However, the NetDataContractSerializer is what I use in CSLA, because it works the same as the BinaryFormatter, but produces and consumes XML instead of a binary blob.

Ahh... didn't notice from the discussions that there were two different serializers.  Good to know.

Brian Criswell replied on Thursday, June 07, 2007

Rocky, this may be a dumb question, but could you use a combination of NDCS and the undoable code to send the information over the DataPortal and back into the same object that it originated from?  In essence, this would mean that you would not need to use the instance = instance.Save() (and have to rehook events, etc.).  You could instead just call instance.Save, even when using the remote DataPortal.

Bowman74 replied on Wednesday, June 06, 2007

I know this may be too easy but have you considered just using the SOAP serializer and being done with it.  SOAP is XML after all so you will be able to read the output in notepad.  It will also do a deep serialization of your objects unlike the XML serializer so you will also be able to see all the private members.  Best of all it will take you about two lines of code, no muss, no fuss.

The only drawback is a bit of extra information about the version of the object so it know how to recreate it and some extra envelope stuff, but that may be important for your debugging too.

Thanks,

Kevin

RSB replied on Wednesday, June 06, 2007

Hi Kevin,

I havent tried SOAP serializer, but does it do the child objects too?

Thanks,
RSB

Bowman74 replied on Wednesday, June 06, 2007

Full deep copy, child objects too.  Basically for deep serialization you have the Binary and SOAP formatters.  Binary is what you are most likely using if you have a remote data portal.  It should be trivially easy for you to try and see if you like the results.  This code will copy it to a file stream so you can look at it but you could just as easily copy it to a memory stream (or any other type of stream) for database persistence.

try 
{
  FileStream fs = new FileStream("mySerializedObject.txt", FileMode.Create);
  SoapFormatter myFormatter = new SoapFormatter();
  myFormatter.Serialize(fs, myObjectInstanceVariable);
}
finally
{
  fs.Close();
}

The nice thing is if you really want to you can they recreate the instance of the object as it was when the error occurred using the Deserialize method or just look through the SOAP text for visual inspection.  Since SOAP messages are XML I suspect they would save to the SQL Server 2005 XML data type but I haven't tried it.  Certainly it would save to a VarChar or any other text type.

Edit to add, don't forget to mark all your CSLA based classes with the Serializable attribute but you should be doing that anyway, particularly if you are ever planning on using a remote data portal.

Thanks,

Kevin

Copyright (c) Marimer LLC