Note that there are some explanatory texts on larger screens.

plurals
  1. POWCF Data Services + JSON throws Exception when adding entity with m:n relations
    text
    copied!<p>I run into a serious problem after changing from Atom to JSON (Light). We use WCF Data Services 5.6 and configured it to use json in order to reduce the amount of data over the wire...</p> <pre><code>{"odata.error":{"code":"","message":{"lang":"de-AT","value":"An error occurred while processing this request."}, "innererror":{"message":"Multiple annotations with the name 'odata.bind' were detected for the property with name 'Employees'. In OData, duplicate annotations are not allowed.","type":"Microsoft.Data.OData.ODataException","stacktrace":" at Microsoft.Data.OData.DuplicatePropertyNamesChecker.AddODataPropertyAnnotation(String propertyName, String annotationName, Object annotationValue)\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightDeserializer.ProcessPropertyAnnotation(String annotatedPropertyName, String annotationName, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue)\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightDeserializer.ParseProperty(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue, String&amp; parsedPropertyName)\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightDeserializer.ProcessProperty(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue, Action`2 handleProperty)\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightEntryAndFeedDeserializer.ReadEntryContent(IODataJsonLightReaderEntryState entryState)\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightReader.ReadAtNavigationLinkEndImplementationSynchronously()\r\n at Microsoft.Data.OData.JsonLight.ODataJsonLightReader.ReadAtNavigationLinkEndImplementation()\r\n at Microsoft.Data.OData.ODataReaderCore.ReadImplementation()\r\n at Microsoft.Data.OData.ODataReaderCore.ReadSynchronously()\r\n at Microsoft.Data.OData.ODataReaderCore.InterceptException[T](Func`1 action)\r\n at Microsoft.Data.OData.ODataReaderCore.Read()\r\n at System.Data.Services.Serializers.EntityDeserializer.ReadEntry(ODataReader odataReader, SegmentInfo topLevelSegmentInfo)\r\n at System.Data.Services.Serializers.EntityDeserializer.Read(SegmentInfo segmentInfo)\r\n at System.Data.Services.Serializers.ODataMessageReaderDeserializer.Deserialize(SegmentInfo segmentInfo)"}}} </code></pre> <p>Our client side code looks like the following snippet:</p> <p><strong>ViewModel</strong></p> <pre><code>//Insert control var control = new Control { Name = this.Name, ShortName = this.ShortName, ////etc... }; this.ControlAgent.AddToContext(control); foreach (var emp in this.EnforcingEmpColl.AddedItems) { this.ControlAgent.AddEnforcingEmployee(control, emp); } this.ControlAgent.SaveControl(control, (s1, e1) =&gt; { ////etc.. }); </code></pre> <p><strong>ControlAgent</strong></p> <pre><code>public class ControlServiceAgent : ServiceAgentBase&lt;Control&gt;, IControlServiceAgent { /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="ControlServiceAgent"/&gt; class. /// &lt;/summary&gt; public ControlServiceAgent() { } /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="ControlServiceAgent"/&gt; class. /// &lt;/summary&gt; /// &lt;param name="uri"&gt;service uri&lt;/param&gt; public ControlServiceAgent(Uri uri) : base(uri) { } /// &lt;summary&gt; /// Adds an Enforcing Emp to the Control /// &lt;/summary&gt; /// &lt;param name="control"&gt;control&lt;/param&gt; /// &lt;param name="emp"&gt;enforcing Employee&lt;/param&gt; public void AddEnforcingEmployee(Control control, Employee emp) { this.Context.AttachTo("Employees", emp, "*"); this.Context.AddLink(control, "Employees", emp); } /// &lt;summary&gt; /// Adds an control to the context /// &lt;/summary&gt; /// &lt;param name="entity"&gt;entity to add&lt;/param&gt; public void AddToContext(Control entity) { this.Context.AddToControls(entity); } /// &lt;summary&gt; /// Adds and saves a control and notifies the tree /// &lt;/summary&gt; /// &lt;param name="entity"&gt;control to add&lt;/param&gt; /// &lt;param name="handler"&gt;callback&lt;/param&gt; public void SaveControl(Control entity, EventHandler&lt;ResponseEventArgs&lt;Control&gt;&gt; handler) { this.Context.BeginSaveChanges(SaveChangesOptions.ReplaceOnUpdate, ar =&gt; { try { DataServiceResponse response = this.Context.EndSaveChanges(ar); Control controlToAdd = null; // Enumerate the returned responses. foreach (ChangeOperationResponse change in response) { // Get the descriptor for the entity. var descriptor = change.Descriptor as EntityDescriptor; if (descriptor != null) { controlToAdd = descriptor.Entity as Control; } } if (controlToAdd == null) { handler(this, new ResponseEventArgs&lt;Control&gt;("[SP-Control]: Error while SaveControl. Saving the added control failed!", null)); } else { handler(this, new ResponseEventArgs&lt;Control&gt;(controlToAdd)); } } catch (Exception e) { handler(this, new ResponseEventArgs&lt;Control&gt;("[SP-Control]: Error while SaveControl. Saving the added control failed!", e)); } }, null); } } </code></pre> <p>}</p> <pre><code>public abstract class ServiceAgentBase&lt;T&gt; : ServiceBase, IServiceAgentBase&lt;T&gt; { /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="ServiceAgentBase&amp;lt;T&amp;gt;"/&gt; class. /// &lt;/summary&gt; protected ServiceAgentBase() : base() { } /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="ServiceAgentBase&amp;lt;T&amp;gt;"/&gt; class. /// &lt;/summary&gt; /// &lt;param name="uri"&gt;service uri&lt;/param&gt; protected ServiceAgentBase(Uri uri) : base(uri) { } /// &lt;summary&gt; /// Attaches an entity to the service context /// &lt;/summary&gt; /// &lt;param name="entity"&gt;entity to attach&lt;/param&gt; public virtual void Attach(T entity) { this.Context.Detach(entity); ////persist changes regardless of whether the underlying entity has changed this.Context.AttachTo(entity.GetType().Name + "s", entity, "*"); } /// &lt;summary&gt; /// Deletes an entity /// &lt;/summary&gt; /// &lt;param name="entity"&gt;entity to delete&lt;/param&gt; public virtual void Delete(T entity) { this.Context.DeleteObject(entity); } /// &lt;summary&gt; /// Updates an entity /// &lt;/summary&gt; /// &lt;param name="entity"&gt;entity to update&lt;/param&gt; public virtual void Update(T entity) { this.Context.UpdateObject(entity); } } </code></pre> <p>The only remarkable thing in ServiceBase is that we create the context and use Json</p> <pre><code> this.Context.Format.UseJson(); </code></pre> <p>If I comment out this line and use Atompub instead, everything works fine... Has anyone of you the same problem? Are there any solutions for that?</p> <p>Thank you!</p> <p><strong>EDIT:</strong></p> <p>Traces from Fiddler</p> <p><strong>JSON:</strong></p> <pre><code>POST http://localhost/MyService/MyDataService.svc/Controls HTTP/1.1 Accept: application/json;odata=minimalmetadata DataServiceVersion: 3.0;NetFx MaxDataServiceVersion: 3.0;NetFx Content-Type: application/json;odata=minimalmetadata {"odata.type":"Ria.DevelopmentModel.Control","Processes@odata.bind": ["http://localhost/MyService/MyDataService.svc/Processes(3)"], "Employees@odata.bind":["http://localhost/MyService/MyDataService.svc/Employees(2627)"], "Employees@odata.bind":["http://localhost/MyService/MyDataService.svc/Employees(2628)"], "Accuracy":false,"Activity":null,"ActualStatus":0,"Automation":null,////All the other properties...} </code></pre> <p><strong>ATOM</strong></p> <pre><code>POST http://localhost/MyService/MyDataService.svc/Controls HTTP/1.1 Accept: application/atom+xml,application/xml Content-Type: application/atom+xml DataServiceVersion: 1.0;NetFx MaxDataServiceVersion: 3.0;NetFx &lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"&gt; &lt;category term="Ria.DevelopmentModel.Control" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /&gt; &lt;link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Processes" type="application/atom+xml;type=feed" title="Processes" href="http://localhost/MyService/MyDataService.svc/Processes(3)" /&gt; &lt;link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Employees" type="application/atom+xml;type=feed" title="Employees" href="http://localhost/MyService/MyDataService.svc/Employees(2627)" /&gt; &lt;link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Employees" type="application/atom+xml;type=feed" title="Employees" href="http://localhost/MyService/MyDataService.svc/Employees(2628)" /&gt; &lt;id /&gt;&lt;title /&gt;&lt;updated&gt;2013-09-18T09:20:07Z&lt;/updated&gt;&lt;author&gt;&lt;name /&gt;&lt;/author&gt;&lt;content type="application/xml"&gt; &lt;m:properties&gt;&lt;d:Accuracy m:type="Edm.Boolean"&gt;false&lt;/d:Accuracy&gt;&lt;d:Activity m:null="true" /&gt;&lt;d:ActualStatus m:type="Edm.Byte"&gt;0&lt;/d:ActualStatus&gt;&lt;d:Automation m:type="Edm.Byte" m:null="true" /&gt; ////All the other props.... </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload