Showing posts with label serialization. Show all posts
Showing posts with label serialization. Show all posts

Friday, 29 April 2016

How to verify that a class is serializable?

Recently I've came into investigating a failing End-to-End test that was failing inside the WCF service with an exception. The exception was related to WCF serialization of the return type of the service. As usually I decided to tackle this issue in the TDD way:

  1. Write a fialing test that reproduces the issue
  2. Write the minimum amount of code to make the test pass
  3. Refactor if needed

I already had a failing End to End test that was failing, but it was a heavy and complex test. All I wanted to a small, fast, isolated and reproducible test that would test only the serialization of that class. We're using FluentAssertions library for readable and intuitive assertions in our unit tests I checked whether it contains a way to verify whether a class would be successfully serialized in WCF. Unfortunately, it had two similar methods:

I need to explain what these methods exactly do for those who are not familiar with them:

  1. Serialize the instance using the selected serialization method: binary or XML
  2. Deserialize the result of the above serialization
  3. Compare the values of the resulted instance with the original one
It was exactly what I needed, but these methods use different serialization methods than WCF. WCF uses DataContract serialization. I decided to contribute to FluentAssertions library and to add the required method. Dennis Doomen generously accepted my pull request and the new method is available in the official nuget package starting from version 4.5.0. Here how it looks like with the new method:


Last but not least: if you encounter into WCF serialization issues, take a look at my post from 2010 with some WCF Serialization Tips.


Thursday, 4 March 2010

Deep cloning object in C#/.NET

I was asked recently to write a generic method for deep cloning of a complex object. The object contains references to other objects, collections, which contain references to many other objects and collections. The method was supposed to work on both platforms: .NET 3.5 (or higher) and Silverlight.

While googling I found a good post listing different approaches for cloning
C# Object Clone Wars

Last technique described in that blog points to Copyable Framework - generic framework for copying/cloning any objects using method extensions

The framework, written by Håvard Stranden addresses most of my requirements, except one: it does not work on Silverlight.

I came up with a simple method that serializes the original object and deserializes it to a cloned copy of it. It can be used as an extension or by implementing IClonable interface:

public static class ObjectExtensions
{
  public static T Clone<T>(this object original)
  {
    T cloned;
    using (MemoryStream stream = new MemoryStream())
    {
      DataContractSerializer serializer = new DataContractSerializer(typeof(T));
      serializer.WriteObject(stream, original);
      stream.Position = 0;
      cloned = (T)serializer.ReadObject(stream);
    }
    return cloned;
  }
}


* This source code was highlighted with Source Code Highlighter.

Tuesday, 9 February 2010

WCF Serialization Tips

Here are a few tips on how to improve WCF performance and traffic by simple putting the right attributes on your serializable classes:


1. "Avoid inferred data contracts (POCO). Always be explicit and apply the DataContract attribute" (C) Juval Löwy
2. "Use the DataMember attribute only on properties or read-only public members" (C) Juval Löwy
3. Mark [DataMember] only properties, that DO have to be serialized. Avoid marking calculated properties as DataMember
2. Consider using (IsReference = true) on classes to avoid data duplication and circular references.
3. Use short (one or two letters) Name on classes and properties to significantly reduce traffic. (C) Eyal Vardi
4. Specify short Value for EnumMember
5. Use parametrized DataContract property for generic classes
6. Use (EmitDefaultValue=false) on properties to reduce traffic

Sample:

[DataContract(Name="CT")]
  public enum CustomerTypes
  {
    [EnumMember(Value = "I")]
    Internal,
    [EnumMember(Value = "E")]
    External,
    [EnumMember(Value = "U")]
    Unknown
  }

  [DataContract(IsReference = true, Name = "B{0}")]
  public class BusinessBase<T>
  {
    T Id { get; set; }
  }

  [DataContract(IsReference = true, Name = "C")]
  public class Customer : BusinessBase<int>
  {
    [DataMember(Name="C", EmitDefaultValue=false)]
    public CustomerTypes CustomerType { get; set; }

    [DataMember(Name = "N", EmitDefaultValue = false)]
    public string Name { get; set; }

    [DataMember(Name = "P", EmitDefaultValue = false)]
    public Customer ParentCustomer { get; set; }

    public bool IsGoodCustomer
    {
      get
      {
        return this.CustomerType == CustomerTypes.Internal || this.CustomerType == CustomerTypes.External;
      }
    }

  }


* This source code was highlighted with Source Code Highlighter.

Monday, 15 June 2009

V2: WCF CollectionDataContract and DataMember attributes

Following Jeff's comment on the first version of this post, here are some explanations and a full class.

Q1. Why did I write "implement IEnumerable" twice?
A1. My original intention was to derive my class from ICollection<T>. Thus I had to implement IEnumerable and IEnumerable<T>.

Q2. Why do I bother to implement IEnumerable at all if the class is not "decorated" as IEnumerable?
A2. ICollection<T> "derives" from IEnumerable<T> and IEnumerable, so we have to implement both of them when writing a class that implements ICollection<T>

Here is a complete class:

 [DataContract]
  public class EntityCollectionWorkaround<EntityType> : ICollection<EntityType>
  {
    #region Constructor
    public EntityCollectionWorkaround()
    {
      Entities = new List<EntityType>();
    }
    #endregion

    [DataMember]
    public int AdditionalProperty { get; set; }

    [DataMember]
    public List<EntityType> Entities { get; set; }

    #region ICollection<T> Members

    public void Add(EntityType item)
    {
      Entities.Add(item);
    }

    public void Clear()
    {
      this.Entities.Clear();
    }

    public bool Contains(EntityType item)
    {
      return Entities.Contains(item);
    }

    public void CopyTo(EntityType[] array, int arrayIndex)
    {
      this.Entities.CopyTo(array, arrayIndex);
    }

    public int Count
    {
      get
      {
        return this.Entities.Count;
      }
    }

    public bool IsReadOnly
    {
      get
      {
        return false;
      }
    }

    public bool Remove(EntityType item)
    {
      return this.Entities.Remove(item);
    }

    public EntityType this[int index]
    {
      get
      {
        return this.Entities[index];
      }
      set
      {
        this.Entities[index] = value;
      }
    }
    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<EntityType> GetEnumerator()
    {
      return this.Entities.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return this.Entities.GetEnumerator();
    }

    #endregion
  }


* This source code was highlighted with Source Code Highlighter.

Thursday, 16 April 2009

WCF CollectionDataContract and DataMember attributes

I came to write this post just occasionally: I was required to add a property to an existing collection. The colleciton was generated on the WCF and was sent to a client. I was surprised to discover, that it's not supported and other people already faced this issue and expressed their frustration and posted different workarounds on the web. Unfortunately, none of these suggestions worked. So I decided to post a tested solution.

So here is the situation, we have an Entity class and a collection of them:
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Collections.Generic;

[DataContract]
public class Entity
{
public int ID {get; set;}
public int Name {get; set;}
}

[CollectionDataContract]
public class EntityCollectionNotSupported : Collection
{
[DataMember]
public int AdditionalProperty { get; set; }
}


* This source code was highlighted with Source Code Highlighter.


It will compile, but will not serialize AdditionalProperty at all! So what can we do about it if EntitiesCollection must stay a Collection?

We can mark our collection as DataContract and wrap another collection inside. Like this:

[DataContract]
public class EntityCollectionWorkaround : ICollection
{
public EntityCollectionWorkaround()
{
Entities = new List();
}

[DataMember]
public int AdditionalProperty { get; set; }

[DataMember]
public List Entities { get; set; }

// Implement here ICollection,
// IEnumerable and IEnumerable members
// by wrapping Entities
}


* This source code was highlighted with Source Code Highlighter.


Hope it helped somebody

Thursday, 17 July 2008

"The constructor to deserialize an object of type 'MyGenericCollection' was not found."

This exception is thrown by an application that tries to deserialize an instance of MyGenericCollection. In my case it was thrown by BizTalk that stores current state of it variables by their serialization and saving into its database. Then it restores the previous state by deserialization.
MyGenericCollection is a class that derives from Dictionary<Key,value>, which is serializable.

So why the deserialization failed?
Because the deserialization is done within constructor which accepts SerializationInfo and StreamingContext, but constructors are not derived. It means that we need to to define such constructor:

public class MyGenericCollection : Dictionary<Key,Value>
{
protected MyGenericCollection(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}