none
Data services client -- exception on saveChanges when processing non-persistent properties on client version of partial class

    Question

  • I am attempting to use the Data Services Client Library to perform updates to objects managed by the Entity Framework.  I built my server-side classes using the designer tool and generated the client-side classes using DataSvcUtil.exe.

    I have then extended, via a partial class, one of the client-side classes to contain derived properties which are used by UI consumers of these objects.

    When I attempt to update one of these objects through the data service client library (using my generated subclass of DataServiceContext), I get the following error:

          Error processing request stream. The property name 'Department' specified for type 'MyData.User' is not valid.

    'User' is my entity class.  'Department' is the property I have defined in my client-side partial 'User' class.

    If I remove the properties from my client-side partial class altogether, the saveChanges call works fine, but this presents other problems.  Basically, I need these properties on the client-side version of this class.

    My hunch is that, during serialization/deserialization, the service is attempting to process this property ('Department') that is not known on the server side.  I have attempted to add a similar partial class on the server side with a similarly named property, but I get the same error.  I have then attempted to use the 'IgnorePropertiesAttribute' markup, again with the same error.  (I believe the 'IgnorePropertiesAttribute' is for hiding server-side properties when exposing data to a client.  I also think I read that this attribute is only relevant when using non-EF objects.  But I was grasping by this time...)

    Is there a way to handle the situation where transient properties need to be defined on a client-side partial class version of an object?

    --rick
    Friday, October 17, 2008 8:57 PM

Answers

  • The Data Services Client Library doesn't know or use the metadata of the server, it only uses the public properties that are on the class instance that it attempts to save.

     

    Currently there is no mechanism other than removing or making the properties you don't want saved non-public from being pushed to the server.

    Friday, October 17, 2008 9:54 PM

All replies

  • The Data Services Client Library doesn't know or use the metadata of the server, it only uses the public properties that are on the class instance that it attempts to save.

     

    Currently there is no mechanism other than removing or making the properties you don't want saved non-public from being pushed to the server.

    Friday, October 17, 2008 9:54 PM
  • Thanks for the answer, Mark.

     

    I hope this is viewed as a deficiency that gets addressed in a future release.  As it stands, the ability to extend an entity class (on the client side) with additional public properties is essentially nullified.  I can make my properties non-public, but that defeats my purpose of having these properties visible to my presentation layer code.

     

    --rick

     

     

    Monday, October 20, 2008 4:30 PM
  • Note that you can make the properties "internal" and the problem will not occur.  It sounds like that may not help you, since it appears that your presentation layer is in a separate assembly from your business logic.  However, I wanted to emphasize that point in case it helps resolve the situation for others that come across this thread.  In my case my presentation logic and business logic is all in the same assembly (a Silverlight app), so marking my client-side properties as internal was sufficient for me.

     

    David

    Wednesday, November 19, 2008 4:19 PM
  • I agree with the OP that this should be treated as a bug. It's a long-standing tradition in every .NET serialization technology to have some attribute to "ignore" properties from the serialization process.

     

    I just converted a bunch of code to use ADO.NET data services and now the whole architecture needs to be changed because it relies very much on these client-only properties being used. The ADO.NET Data Services client seems to be very limited, which I guess is to be expected since it was introduced in a service pack. But things such as no property change notification and using non-observable collections make the generated code very difficult to work with in a GUI.

     

    The last two I have been able to work around by running a PowerShell script over the generated source. But the issues with the partial class properties is unavoidable as far as I can tell.

    Monday, November 24, 2008 11:28 PM
  • We seem to have a catch-22 here.  As (at least on my system), the property must be "public" so you can databind to it.  So if you want a calculated (readonly) property, it must be public for the binding fx to see it.  When I mark it internal, the binding framework throws error.

     

    Not a DS issue, but the binding framework should take a lambda as an option for calculated fields in place of the DataMember parm.

    Friday, December 05, 2008 6:05 PM
  • Came up with hack to have displaymember (i.e. combobox) display a calculated field.  Workaround if you can't add a partial Property to a class because of serialization.  Far from perfect, but may get you down the road for some issues.  If they just ignored properties with only Getters, this would be easier.

     

    this.cbEmployees.DisplayMember = "xxx"; // Member not exists, so displays value of ToString.

    this.cbEmployees.ValueMember = "EmployeeID";

    this.cbEmployees.DataSource = db.GetEmployees().ToList(); // Order important. If you set DataSource before DisplayMember, it binds DisplayMember to ValueMember. We want it to bind to "ToString()".

    Friday, December 05, 2008 7:31 PM
  • Have you considered binding to the original member but use a Converter to perform the calculation/manipulation of the value?

    Tuesday, December 09, 2008 10:52 PM
  •  Reading the OP's description of what he/she wants to achieve is to have extra properties on the client side which are not Sent to the Server.
     There is no way to do this automatically , but there are appropriate Hooks for you to remove certain properties from being sent to the server.
     The DataServiceContext has a WritingEntity Event that  allows one to customize the Payload that is sent to the Server.
     The code to achieve this would look something like this :

     ContextInstance.WritingEntity += new EventHandler<ReadingWritingEntityEventArgs>(WritingEntityHandler);

     void WritingEntityHandler(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  

                //The XName of the Element to find in the payload
                XName xnEntityProperties = XName.Get("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");

                //The XName of the new Property we are going to remove from the payload
                XName xnProperty = XName.Get("Department", "http://schemas.microsoft.com/ado/2007/08/dataservices");

                //Get the Properties of the entity
                XElement xeEntityProperties = e.Data.Descendants().Where<XElement>(xe => xe.Name == xnEntityProperties).First<XElement>();

                //Get the Property of the entity  you don't want sent to the server
                XElement xeRemoveThisProperty = xeEntityProperties.Where<XElement>(xe => xe.Name == xnProperty).First<XElement>();

                //Remove this property from the Payload sent to the server
                xeRemoveThisProperty.Remove();

    }

    Hope this helps
    Phani Raj Astoria
    Thursday, December 11, 2008 9:47 PM

  • Further to Phani's post, here's a solution that removes serialized data for read-only properties and those properties marked with an 'AstoriaIgnore' attribute.


        [System.AttributeUsage(AttributeTargets.Property)]
        public sealed class AstoriaIgnoreAttribute : Attribute
        {
        }

        void ContextInstance_WritingEntity(object sender, ReadingWritingEntityEventArgs e)
        {
            string datans = "http://schemas.microsoft.com/ado/2007/08/dataservices";

            var ignorePropertyNames = e.Entity.GetType()
                .GetProperties()
                .Where(pd => pd.GetSetMethod() == null
                          || pd.GetCustomAttributes(typeof(AstoriaIgnoreAttribute), true).Any())
                .Select(pd => pd.Name)
                .ToArray();

            if (ignorePropertyNames.Length > 0)
            {
                var dataElements = e.Data
                    .Descendants()
                    .Where(d => d.Name.NamespaceName == datans)
                    .Join(ignorePropertyNames, d => d.Name.LocalName, ipn => ipn, (d, ipn) => d)
                    .ToArray();

                foreach (var element in dataElements)
                {
                    element.Remove();
                }
            }
        }

    Thursday, December 11, 2008 11:28 PM
  • I just posted something on my blog which uses an Attribute to specify which properties to ignore :)

    Customizing Serialization of Entities in the ADO.NET Data Services Client Library
    Phani Raj Astoria
    Thursday, December 11, 2008 11:38 PM