CodeSmith Community
Your Code. Your Way. Faster!

No More Writing IPropertySerializers! ..?

Latest post 05-15-2008 9:31 PM by blake05. 8 replies.
  • 02-14-2008 3:28 PM

    • akidan
    • Top 500 Contributor
    • Joined on 02-14-2008
    • Posts 19
    • Points 433

    No More Writing IPropertySerializers! ..?

    [2/25/2008: Updated AnyPropertySerializer.zip to reflect latest changes by ejsmith]

    Hi all,

    I've written a simple class (with source; attached) that will serialize any property of any type, so long as all members are marked Serializable.

    Which means: no more writing serializers by hand for your types, and you can now serialize collections (lists, dictionaries, etc) with ease. Yay!

    It works well (hence the "!"), but has a couple kinks I can't figure out (hence the "..?"). It requires that you have .NET 3.0+ installed, as it uses WCF's DataContractSerializer.

    A simple example:
    <%@ CodeTemplate Language="C#" %>
    <%@ Property Name="MyDogs" Type="List<Dog>" Serializer="AnyPropertySerializer" %>
    <%@ Assembly Name="AnyPropertySerializer" %>
    <%@ Import Namespace="RHencke.CodeSmith" %>
    <%@ Import Namespace="System.Collections.Generic" %>

    <script runat="template">
    [Serializable]
    public class Dog
    {
        public string Name { get { return _Name; } set { _Name = value; } } string _Name;
        public bool IsWagging { get { return _IsWagging; } set { _IsWagging = value; } } bool _IsWagging;
    }
    </script>


    That should do it! MyDogs should pop up in your property window. It will use the built in TypeUIEditor for editing, and AnyPropertySerializer for saving. You can test it out by adding some dogs, saving the values to a .cst, and loading it up again, or by copying the properties.

    Now, the stuff I can't figure out...
    • Compiling the template the first time does not produce the list as expected; you need to compile the template twice.
    • Compiling the template after modifying the property results in the odd error:
          Object of type 'System.Collections.Generic.List`1[_CodeSmith.ClassGen_cst+Dog]' cannot be converted to type 'System.Collections.Generic.List`1[_CodeSmith.ClassGen_cst+Dog]'.,
      after which the property resets until loaded from disk.

    Example saved properties:
    <codeSmith xmlns="http://www.codesmithtools.com/schema/csp.xsd">
      <propertySets>
        <propertySet output="ClassGen.txt" template="x:\CodeSmith\Templates\ClassGen.cst">
          <property name="MyDogs">
            <ArrayOfClassGen_cst.Dog xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/_CodeSmith">
          <ClassGen_cst.Dog>
            <_IsWagging>false</_IsWagging>
            <_Name>Mister Waggy</_Name>
          </ClassGen_cst.Dog>
          <ClassGen_cst.Dog>
            <_IsWagging>true</_IsWagging>
            <_Name>Buttons</_Name>
          </ClassGen_cst.Dog>
        </ArrayOfClassGen_cst.Dog>
          </property>
        </propertySet>
      </propertySets>
    </codeSmith>


    Please let me know your thoughts/fixes/complaints - thanks!

    Robert Hencke
    • Post Points: 35
  • 02-15-2008 9:58 AM In reply to

    • ejsmith
    • Top 10 Contributor
    • Joined on 12-28-2002
    • Dallas, TX USA
    • Posts 2,205
    • Points 922,460

    Re: No More Writing IPropertySerializers! ..?

    Robert,

    Great idea!  We currently support any object that is XmlSerializer ready, but this makes it so you could serialize anything.  Nice.

    Eric J. Smith
    CodeSmith Tools, LLC
    Chief Software Architect

    • Post Points: 5
  • 02-15-2008 8:44 PM In reply to

    • akidan
    • Top 500 Contributor
    • Joined on 02-14-2008
    • Posts 19
    • Points 433

    Re: No More Writing IPropertySerializers! ..?

    [edit] The code in the zip doesn't work as is - it needs to be changed so the XmlWriter omits the XML declaration. As is probably obvious, this is a work in progress.

    I've fixed the above errors I was encountering (and some others unmentioned), at a slight cost to simplicity. My code to parse default values is still pretty lame, but at least this fixes the previous problems.

    The syntax is now:
    <%@ Property Name="MyDogs" Type="List<Dog>" Serializer="AnyPropertySerializer" Default="new" %>

    This ensures that the ParseDefaultValue code is run on first compile.

    Values are now loaded and saved to/from XML between compiles instead of the raw type, which fixes the problem where the property value would not restore after compilations.

    The next issue to tackle is dealing with serialization problems in the face of changing class definitions (e.g. adding a property to the Dog class). I've started to look into IDataContractSurrogate, but haven't really gotten anywhere yet.

    As always, please feel free to share your thoughts - thanks!

    Robert Hencke
    • Post Points: 5
  • 02-16-2008 2:46 PM In reply to

    • akidan
    • Top 500 Contributor
    • Joined on 02-14-2008
    • Posts 19
    • Points 433

    Re: No More Writing IPropertySerializers! ..?

    After experimenting a lot, the simplest way to make serialization work with a constantly changing class is to simply mark the private fields with System.Runtime.Serialization.OptionalFieldAttribute. Ideally, we could use CodeSmith's built-in CodeSmith.Engine.OptionalAttribute for this, but the code in WCF's serializer that checks for this specific attribute is buried pretty deep...

    Example:

    [Serializable]
    class Dog
    {
        public string Name { get { return _Name; } set { _Name = value; } }
        [OptionalField] string _Name;

        public bool IsWagging { get { return _IsWagging; } set { _IsWagging = value; } }
        [OptionalField] bool _IsWagging;
    }


    This fixes most of the major issues with AnyPropertySerializer; the final piece will probably be figuring out the best way to use and parse default values for properties.
    • Post Points: 35
  • 02-25-2008 1:13 PM In reply to

    • ejsmith
    • Top 10 Contributor
    • Joined on 12-28-2002
    • Dallas, TX USA
    • Posts 2,205
    • Points 922,460

    Re: No More Writing IPropertySerializers! ..?

    I made some updates to this that should make it work a little better.

    Eric J. Smith
    CodeSmith Tools, LLC
    Chief Software Architect

    • Post Points: 35
  • 02-25-2008 2:02 PM In reply to

    • akidan
    • Top 500 Contributor
    • Joined on 02-14-2008
    • Posts 19
    • Points 433

    Re: No More Writing IPropertySerializers! ..?

    Excellent, thanks! I updated the top download link to include your changes. :)
    • Post Points: 35
  • 05-12-2008 8:35 PM In reply to

    • blake05
    • Top 25 Contributor
    • Joined on 04-03-2008
    • Wisconsin
    • Posts 417
    • Points 7,640

    Re: No More Writing IPropertySerializers! ..?

     I have found a bug where you can't serialize the TableSchema Object. Here is the sample code.

    public class TempCodeBehindClass : CodeTemplate
    {
        private TableSchemaItems _tableSchemaItemCollection = new TableSchemaItems();
       
        public TableSchemaItems tsCollection
        {
            get { return _tableSchemaItemCollection;}
            set {_tableSchemaItemCollection = value;}
        }
    }

    [Serializable()]
    [PropertySerializer(typeof(AnyPropertySerializer))]
    public class TableSchemaItems : System.Collections.Generic.List<TableSchemaItem>
    {
    }

    [Serializable()]
    public class TableSchemaItem
    {
        private TableSchema _TableSchema;
               
        public TableSchema TableSchema
        {
        get { return _TableSchema; }
        set { _TableSchema = value; }
        }
    }

     Below is the stack trace...

    Stacktrace:
    at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
    at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
    at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
    at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContract(Int32 id, RuntimeTypeHandle typeHandle)
    at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)

    Message=Type 'SchemaExplorer.TableSchema' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.
    Data=System.Collections.ListDictionaryInternal

     Does anyone have a (quick) fix, where I don't have to include the .net 3.0+ attribute to the codebehind?

    Blake Niemyjski

    CodeSmith Tools, LLC Support Specialist

    Blog: http://windowscoding.com/blogs/blake/

    ----------------------------------------------------------------------
     Member of the .NetTiers team | Visit http://www.nettiers.com
    ----------------------------------------------------------------------

    • Post Points: 35
  • 05-15-2008 11:17 AM In reply to

    • akidan
    • Top 500 Contributor
    • Joined on 02-14-2008
    • Posts 19
    • Points 433

    Re: No More Writing IPropertySerializers! ..?

    Reply |Contact |Answer
    Hey, Blake.

    The problem is that TableSchema class itself is not marked with SerializableAttribute or DataContractAttribute, so the serializer doesn't know how to serialize it.

    I might try adding support for detecting CodeSmith style PropertySerializerAttribute markings, but for now, your best bet's probably to stick with the CodeSmith serialization.
    • Post Points: 35
  • 05-15-2008 9:31 PM In reply to

    • blake05
    • Top 25 Contributor
    • Joined on 04-03-2008
    • Wisconsin
    • Posts 417
    • Points 7,640

    Re: No More Writing IPropertySerializers! ..?

     Thank you

    Blake Niemyjski

    CodeSmith Tools, LLC Support Specialist

    Blog: http://windowscoding.com/blogs/blake/

    ----------------------------------------------------------------------
     Member of the .NetTiers team | Visit http://www.nettiers.com
    ----------------------------------------------------------------------

    • Post Points: 5
Page 1 of 1 (9 items) | RSS
Copyright © 2008 CodeSmith Tools, LLC
Powered by Community Server (Commercial Edition), by Telligent Systems