Customizing Serialization of Entities in the ADO.NET Data Services Client Library

This post is inspired by this forum thread :Data services client -- exception on saveChanges

Problem Statement

I have added some custom proeprties to the Entity Types Generated by DataSvcUtil.exe /Add Service Reference / Hand Coded ,
these properties do not exist on the server and should not be sent to the server .
When I try to save an object of a Type which has custom client-Side only properties to the Data Service using AddObject and SaveChanges,
I get the following error :

 Error processing request stream. The property name '{PropertyName}' specified for type '{TypeName} is not valid

This error is basically from the server telling the client library that its sending a payload which does not seem to match the definition
of the Entity Type on the server.

We can solve this problem by customizing the Payload that the client generates when it sends the entity to the server.
The DataServiceContext exposes an event called WritingEntity that is fired right before we send the payload over the wire.

Its argumentlist contains ReadingWritingEntityEventArgs which gives you access to the Entity Instance being Serialized ( e.Entity ) 
and the ATOM Payload (e.Data ) we are about to send to the Server.

Removing a property from the ATOM Payload that is being sent to the server.
 void dataContext_WritingEntity(object sender, ReadingWritingEntityEventArgs e) {

    // e.Data gives you the XElement for the Serialization of the Entity 
    //Using XLinq  , you can  add/Remove properties to the element Payload  
    XName xnEntityProperties = XName.Get("properties", e.Data.GetNamespaceOfPrefix("m").NamespaceName);
    XElement xePayload = e.Data.Descendants().Where<XElement>(xe => xe.Name == xnEntityProperties).First<XElement>();
   //The XName of the property we are going to remove from the payload
    XName xnProperty = XName.Get(“{PropertyName}”, e.Data.GetNamespaceOfPrefix("d").NamespaceName);

    //Get the Property of the entity  you don't want sent to the server
    XElement xeRemoveThisProperty = xePayload.Descendants().Where<XElement>(xe => xe.Name == xnProperty).First<XElement>();
    //Remove this property from the Payload sent to the server 
     xeRemoveThisProperty.Remove();

     }
}

Generalizing this further , we want to make it easier to customize the serialization of multiple entity types without having to write
multiple copies of the WritingEntity event handler.
We will add an attribute that specfies that a certain CLR property should not be serialized in the ATOM Payload when the client library
sends the entity to the server.

     /// <summary>
    /// Properties marked with this Attribute are not serialized in the payload when sent to the server
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class DoNotSerializeAttribute : Attribute
    {
    }

Now , we change the WritingEntity Event handler to remove any property  that has this attribute on it .

         void DataServiceContextEx_WritingEntity(object sender, ReadingWritingEntityEventArgs e)
        {
            // e.Data gives you the XElement for the Serialization of the Entity 
            //Using XLinq  , you can  add/Remove properties to the element Payload  
            XName xnEntityProperties = XName.Get("properties", e.Data.GetNamespaceOfPrefix("m").NamespaceName);
            XElement xePayload = null;
            foreach (PropertyInfo property in e.Entity.GetType().GetProperties())
            {
                object[] doNotSerializeAttributes = property.GetCustomAttributes(typeof(DoNotSerializeAttribute), false);
                if (doNotSerializeAttributes.Length > 0)
                {
                    if (xePayload == null)
                    {
                        xePayload = e.Data.Descendants().Where<XElement>(xe => xe.Name == xnEntityProperties).First<XElement>();
                    }
                    //The XName of the property we are going to remove from the payload
                    XName xnProperty = XName.Get(property.Name, e.Data.GetNamespaceOfPrefix("d").NamespaceName);
                    //Get the Property of the entity  you don't want sent to the server
                    XElement xeRemoveThisProperty = xePayload.Descendants().Where<XElement>(xe => xe.Name == xnProperty).First<XElement>();
                    //Remove this property from the Payload sent to the server 
                    xeRemoveThisProperty.Remove();
                }
            }
        }

We can encapsulate this functionality into its own class and any DataServiceContext type that inherits from this class should be able to
inherit this functionality too .
Complete Source Code :

Using this in your applications :

Create a partial class with the same name as shown above and include it in your application to get this behavior.

Attribute your types with the DoNotSerializeAttribute  attribute so that this property is not serialized.

  public class TestType
    {
        public int ID { get; set; }
        /// <summary>
        /// This Property is client-only , should not be sent to the server
        /// </summary>
        [DoNotSerialize]
        public string ClientOnlyProperty { get; set; }
    }