Home > OS >  Issue with WCF type serialization
Issue with WCF type serialization

Time:12-14

I'm facing a strange issue with WCF serialization. My project has a type named RefEntity which has a property of another type named RefDomain. A WCF service defines two methods, one takes type RefEntity as parameter, and another takes type RefDomain as parameter.

The method with the RefDomain parameter doesn't seem to serialize the object as all the properties have null value on the service side. Whereas, the method with RefEntity parameter (and RefDomain as a member) works as expected (RefDomain member is serialized as expected).

What am I missing here?

public class RefDomain
{
    private string name;
    private RefDomain parent;
    private Type entityType;

    public string Name
    {
        get => this.name;
        protected set => this.name = value;
    }

    public RefDomain Parent
    {
          get => this.parent;
          protected set => this.parent = value;
    }

    public Type RefEntityType
    {
          get => this.entityType;
          protected set => this.entityType = value;
    }
}

CodePudding user response:

Your properties have protected setters, and DataContractSerializer will only serialize properties that are fully public, unless marked with data contract attributes.

Once you apply the necessary [DataContract] and [DataMember] attributes, you will discover a second problem, namely that DataContractSerializer cannot serialize values of type System.Type. (Demo fiddle #1 here). To serialize your Type RefEntityType property, you will need to use some sort of surrogate for Type that can be serialized, for instance a string.

Thus the following version of RefDomain can be serialized via the data contract serializer:

public class RefDomain
{
    private string name;
    private RefDomain parent;
    private Type entityType;

    [DataMember]
    public string Name
    {
        get => this.name;
        protected set => this.name = value;
    }

    [DataMember]
    public RefDomain Parent
    {
          get => this.parent;
          protected set => this.parent = value;
    }

    public Type RefEntityType
    {
          get => this.entityType;
          protected set => this.entityType = value;
    }

    [DataMember(Name = "RefEntityType")]
    string RefEntityTypeString 
    {
        get
        {
            return RefEntityType?.FullName;
        }
        set
        {
            // Note that simply deserializing a type supplied over the wire will make your application vulnerable to type injection attacks,
            // in which an attacker tricks you into constructing a type that effects an attack when constructed, deserialized or disposed.  
            // This is a known vulnerability with Json.NET's TypeNameHandling.None.  See for details
            // https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf
            // https://stackoverflow.com/questions/39565954/typenamehandling-caution-in-newtonsoft-json/
            // https://stackoverflow.com/questions/49038055/external-json-vulnerable-because-of-json-net-typenamehandling-auto
            var type = value == null ? null : Type.GetType(value);
            // Check the type against a whitelist here?
            RefEntityType = type;
        }
    }
    
    // Your class was had no way to set the protected properties, so I added a parameterized constructor.
    public RefDomain() { }
    public RefDomain(string name, RefDomain parent, Type entityType) => (this.name, this.parent, this.entityType) = (name, parent, entityType);
}

Notes:

Demo fiddle #2 here.

CodePudding user response:

As far as I know, user-defined types used in wcf need to be tagged with the Data Contract attribute, and members need to be tagged with the Data Member attribute.

You can either mark RefDomain as a Data Contract attribute or create a separate class to hold data from RefDomain and pass it through wcf.

  • Related