views:

46

answers:

2

I currently have a WCF service which provides an object graph of data on request. I want to have a mechanism where the client can compute a hash on the cached object graph it posses and can then supply this hash value to the WCF service to see if it matches the data the service possesses.

I tried this using a standard cryptographic algorithm for computing a hash on the objects but as the object definitions are held by the service, when this is transmitted to the client extra properties can be added and the order of the properties may change, both of which will affect the hash produced.

Is there any mechanism other than say overriding GetHashCode on each object on the WCF service definition and then re-implementing the same kind of hash generation as a utility on the client?

+1  A: 

You could simply serialize it to a known layout and take a known hash (md5?) of the serialised form. This requires a predictable serialization though - so XML attributes would be a pain as would whitespace. But not insurmountable.

Alternatively, a reflection / md5 based approach?

Marc Gravell
Creating a hash (i was using RIPEMD-160, maybe a slight overkill) on the serialised form was what i attempted to begin with. I was just using the standard XmlSerialiser for this though. As WCF adds extra properties on retieval (ExtensionData) and it re-orders them the serialised form on the client side was different. Are you recommending creating my own custom serialiser so I know what properties and in which order they are serialised?
gouldos
+1  A: 

Managed to sort this out now. Rather than using an XMLSerialiser on the client and server to create a memory stream that I could then compute a hash on I changed it to use the DataContractSerializer which the WCF service is using to serialise the object graph to the client. This then means that the object graphs are of the same structure and layout. Computing the hash on both serialised forms now matches.

Just in case anyones interested this is how its working, I'm calling this then comparing the byte[] returned with that supplied by the client:

        private static byte[] CalculateHashCode(SomeComplexTypeDefinedAsDataContract objectGraph)
    {
        using (RIPEMD160 crypto = new RIPEMD160Managed())
        {
            using (MemoryStream memStream = new MemoryStream())
            {
                DataContractSerializer x = new DataContractSerializer(typeof(SomeComplexTypeDefinedAsDataContract ));
                x.WriteObject(memStream, objectGraph);
                memStream.Position = 0;
                return crypto.ComputeHash(memStream);
            }
        }
    }
gouldos