0
votes

I am trying to pass an object (actually reference) of MyData in a method but getting exception. Channel type is NetTcpBinding.

System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://tempuri.org/:myData. The InnerException message was 'Type 'System.RuntimeType' with data contract name 'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details. ---> System.Runtime.Serialization.SerializationException: Type 'System.RuntimeType' with data contract name 'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

[DataContract]
[KnownType(typeof(System.Type))] //Keeping it here or removing does not make any difference
public class MyData
{
    private Type m_MyType = typeof(string);
    [DataMember]
    public Type MyType //WCF does not like this. If removed of data type changed then ok 
    {
        get { return m_MyType; }
        set { m_MyType = value; }
    } 

    private Int32 m_Member1 = 0;
    [DataMember]
    public Int32 Member1
    {
        get { return m_Member1; }
        set { m_Member1 = value; }
    }
}
2

2 Answers

4
votes

This is one reason why you should not return Type from WCF operations.

I suggest you return Type.AssemblyFullyQualifiedName instead of Type. Then on the calling end you could:

var type = Type.GetType(returnedTypeName);

If you want to use the Type for creating new objects etc.

0
votes

One solution, even though it may not be the best (this solution is much more general and can allow you to use any binary serializable object), could be to manually serialize your class, sending a byte[] through WCF and to deserialize it upon reception :

    public static byte[] Serialize(Object _obj)
    {
        if (_obj == null)
            return null;

        byte[] Result = null;

        BinaryFormatter bf = new BinaryFormatter();
        using (MemoryStream memStream = new MemoryStream())
        {
            bf.Serialize(memStream, _obj);
            Result = memStream.ToArray();
        }

        return Result;
    }

And here is for Deserialization :

    public static Object Deserialize(byte[] _arrBytes)
    {
        Object obj = null;
        using (MemoryStream memStream = new MemoryStream())
        {
            BinaryFormatter binForm = new BinaryFormatter();
            memStream.Write(_arrBytes, 0, _arrBytes.Length);
            memStream.Seek(0, SeekOrigin.Begin);

            lock (assemblyResolveLocker)
            {
                assemblyCmpt = 0;
                AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

                obj = (Object)binForm.Deserialize(memStream);

                AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            }

        }

        return obj;
    }

And here is the Assembly Resolver I use to manually charge dll to resolve custom types problems (As you can guess, DllPaths is a list containing the paths to the dll I may have to use) :

    private static object assemblyResolveLocker = new object();
    private static int assemblyCmpt = 0;

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (assemblyCmpt < Conf.DllPaths.Count)
        {
            try
            {
                int c = 0;
                foreach (string _path in Conf.DllPaths)
                {
                    if (c < assemblyCmpt)
                    {
                        c++;
                    }
                    else
                    {
                        //Load my Assembly 
                        Assembly assem = Assembly.LoadFile(_path);
                        if (assem != null)
                            return assem;
                    }
                }

            }
            catch { ;}

            return Assembly.GetExecutingAssembly();
        }
        else
        {
            return Assembly.GetExecutingAssembly();
        }
    }

I hope it can help !