IList and Round-trip Serialization Issue in WCF

Problem

WCF throws System.ExecutionEngineException when deserializing and consuming data contracts with IList based attributes.

Forces

  • Collection is changed as immutable when using IList
  • Unable to convert it to List
  • Unable to send it back to service consumer if required

Solution

Let us define a data contract Dump which contains IList of InternalDump.

 
[DataContract]
public class InternalDump
{
    [DataMember]
    public string Part;
}
[DataContract]
public class Dump
{
    [DataMember]
    public string Name;
    [DataMember]
    public IList Parts;
 

    public Dump()
    {
        Parts = new List();
    }
}

I’ve declared a simple WCF service

[ServiceContract]
public interface IService1
{
    [OperationContract]
    Dump GetData(Dump d);
}
 

public class Service1 : IService1
{
    public Dump GetData(Dump d)
    {       
        return d;
    }
}

 You are noticed that GetData just returns the deserialized “d” as a return value to the consumer.  Being a .NET client, the consumer of this service as

Dump d = new Dump();
d.Name = "Roundtrip";
InternalDump id = new InternalDump();
id.Part = "Client";
d.Parts.Add(id);
 

ServiceReference1.Service1Client sc = new DumpConsole.ServiceReference1.Service1Client();
Dump sd = sc.GetData(d);

foreach (InternalDump id2 in sd.Parts)
{
    Console.Write(id2.Part);
}

At the consumer side, a new instance of Dump and InternalDump have been created, serialized and send it as input parameter for GetData.  At the service side, the probelm is when deserializing the IList, WCF internally convert it into InternalDump[] which makes all the problem 1 and 2 mentioned in Forces section.

The problem is not in any of the above code, instead WCF itself.  The world’s so extensible ESB (enterprise service bus) framework assumed and convert IList into T[] for platform neutral.

Unfortunately, do not know the root cause of problem 3 mentioned in “Forces” section.  The solution is not the technical one, but a guideline.

Don’t use IList for the above mentioned probelms.  Instead use List.

Hope WCF in .NET 4.0 will resolve this issue.

Share This: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us

5 Comments

  • Anonymous wrote:

    This is a Bug in WCF and .NET 3.5, it is fixed in the latest version. using List will help you avoid the issue.

    Respond to this
    • udooz wrote:

      Thanks for the information.

      Respond to this
  • Phyo wrote:

    Latest .net 3.5 sp1 fix this issues … but only on Windows 7. The same code runs ok on windows 7 but give all sorts of trouble when running on windows XP or windows 2003.

    Respond to this
    • udooz wrote:

      Thanks Phyo.

      Respond to this
  • Vongsi wrote:

    Hi All expert

    How can I return an IList in WCF service?
    Example (Do this to paging in WCF and NHibernate):
    - want to get all students have class id = classID
    - Add matched students and it’s total in to an IList then return that IList
    - On client site use javascript to get students objects and the total

    Below is my example:

    public IList Get_StudentByClass(string classID)
    {
    using (ISession session = _sessionFactory.OpenSession())
    {
    ICriteria criteria = session.CreateCriteria(typeof(StudentObj));
    IMultiCriteria multiCriteria = session.CreateMultiCriteria();

    criteria.CreateAlias(“classObj”, “clAlias”);

    criteria.Add(Expression.Eq(“clAlias.ClassID”, Convert.ToInt32(classID)));

    using (ITransaction tx = session.BeginTransaction())
    {
    IList multiResults = multiCriteria
    .Add(criteria.SetMaxResults(5))
    .Add(criteria.SetProjection(Projections.RowCount()))
    .List();

    IList results = new ArrayList();
    IList students = (IList)multiResults[0];
    IList counts = (IList)multiResults[1];
    int count = (int)counts[0];

    results.Add(students);
    results.Add(counts);

    tx.Commit();

    session.Evict(criteria);
    session.Flush();
    session.Dispose();
    _sessionFactory.Dispose();
    _sessionFactory.Close();

    results.Add(matchObjects);

    return results;
    }
    }
    }

    Thanks in advance

    Respond to this

Leave a Reply