Failed to deserialize change-set. Operation is not valid due to the current state of the object.

I’ve had a long disucssion with myself over on the MSDN forums here:
http://forums.silverlight.net/forums/p/140254/313870.aspx#313870

I’ve reproduced it here:

I’ve written a domain service that allows basic CRUD operations for a person’s “Contacts”.  Lots and lots of unit tests run just fine against the server side code, and the Silverlight client can download all the contacts I put into the database using a SQL script and display them very nicely.

Unfortunately, I can’t create a new contact from the Silverlight side.  In the submit operation’s completed event handler I get the error message:

{System.Windows.Ria.Data.EntityOperationException:
Failed to deserialize change-set. Operation is not valid due to the current state of the object.
at System.Windows.Ria.Data.HttpDomainClient.GetRequestResult(HttpDomainClientAsyncResult httpAsyncResult)
at System.Windows.Ria.Data.HttpDomainClient.EndSubmitCore(IAsyncResult asyncResult)
at System.Windows.Ria.Data.DomainClient.EndSubmit(IAsyncResult asyncResult)
at System.Windows.Ria.Data.DomainContext.CompleteSubmitChanges(IAsyncResult asyncResult)}

However,  in the submit operation completed event handler submitOp.EntitiesInError.Count()=0.  Thus, it doesn’t seem to be my new contact instance object that’s the problem.

I’ve overriden all the methods in the domain service adding try/catch blocks (or at least a breakpoint) and just calling base.whatever()  the only method that seems to be called is the Initialize(DomainServiceContext context) method, which completes normally.  The insert method of the domain service is definitely not called:

[Insert]
 public void AddContact( ContactDto newContact ) {
    Contract.Requires(GetCurrentUserId()!=null, "The request must be authenticated");
    Contract.Requires(newContact!=null, "The contact to add must not be null");
    Contract.Requires(newContact.Id==0, "All new contacts must have a zero ID");
    Contract.Ensures(newContact.Id!=0, "The contact's ID should not be zero after adding it to the database");
    System.Diagnostics.Trace.WriteLine("*** SERVER *** AddContact( "+ newContact + " )");
    var userID = GetCurrentUserId();
    this.UnitOfWork.SaveContact(userID, newContact);
 }

The JSON that is passed to the server is:

[{"Entity":{"__type":"Contact:#MyApplication.DataAccessLayer.Contracts.Data",
"Archived":null,
 "Category":null,
 "Company":"ABC inc",
 "DataVersion":null,
 "DateCreated":"\/Date(-621355788000000500)\/",
 "DateModified":null,
 "DateViewed":null,
 "FirstName":"Robert",
 "HomeAddressId":null,
 "Id":0,
 "LastName":"McCarter",
 "Notes":null,
 "NotificationFrequency":null,
 "OwnerId":0,
"SpouseFirstName":null,
 "SpouseLastName":null,
 "WorkAddressId":null},
"Id":0,
 "Operation":1,
 "OperationData":null,
 "OperationName":null}]

So, in a separate solution I started from scratch and created a new Silverlight  .NET RIA Services project. I copied the definition of the DTO contact class into this new project.  I can easily create new instances of the DTO contact class in the new project.   Then I copied my simplified GUI in to the original project and it doesn’t work, I get the same error as above.  Then I copied my simplified domain service to the original project and it STILL doesn’t work, I get the same error.

The contact DTO class was being automatically generated by my ORM tool, and was being annotated by that tool as follows:

[System.Runtime.Serialization.DataContract(Name="Contact")]
public partial class ContactDto : BaseEntityDto {
....
}

When I had previously copied the DTO code to my simplified experimentation project I had not copied the attributes.  The moment I copied the attributes it stopped working.  Changing the name of the data contract to match the name of the class fixes the problem.

Notice that this is actually visible in the original JSON:

    Contact:#MyApplication.DataAccessLayer.Contracts.Data

this should have been

    ContactDto:#MyApplication.DataAccessLayer.Contracts.Data

I don’t know WCF so I don’t fully understand what this name is actually doing, although according to the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx) the default value is the name of the class.

Is it possible that this is a bug in .NET RIA Services, where RIA Services is assuming the data contract name is the same as the class name even when it doesn’t have to be?

Update:

I’ve asked Mindscape if LightSpeed could be modified to make this work:
http://www.mindscape.co.nz/forums/Post.aspx?ThreadID=2507&PostID=7399

 

 

No comments yet

Leave a comment