从 Atom 更改为 JSON (Light) 后,我遇到了一个严重的问题。我们使用 WCF 数据服务 5.6 并将其配置为使用 json 以减少通过网络传输的数据量...
{"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& 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)"}}}
我们的客户端代码如下所示:
视图模型
//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) => { ////etc.. });
控制代理
public class ControlServiceAgent : ServiceAgentBase<Control>, IControlServiceAgent
{
/// <summary>
/// Initializes a new instance of the <see cref="ControlServiceAgent"/> class.
/// </summary>
public ControlServiceAgent()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ControlServiceAgent"/> class.
/// </summary>
/// <param name="uri">service uri</param>
public ControlServiceAgent(Uri uri)
: base(uri)
{
}
/// <summary>
/// Adds an Enforcing Emp to the Control
/// </summary>
/// <param name="control">control</param>
/// <param name="emp">enforcing Employee</param>
public void AddEnforcingEmployee(Control control, Employee emp)
{
this.Context.AttachTo("Employees", emp, "*");
this.Context.AddLink(control, "Employees", emp);
}
/// <summary>
/// Adds an control to the context
/// </summary>
/// <param name="entity">entity to add</param>
public void AddToContext(Control entity)
{
this.Context.AddToControls(entity);
}
/// <summary>
/// Adds and saves a control and notifies the tree
/// </summary>
/// <param name="entity">control to add</param>
/// <param name="handler">callback</param>
public void SaveControl(Control entity, EventHandler<ResponseEventArgs<Control>> handler)
{
this.Context.BeginSaveChanges(SaveChangesOptions.ReplaceOnUpdate,
ar =>
{
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<Control>("[SP-Control]: Error while SaveControl. Saving the added control failed!", null));
}
else
{
handler(this, new ResponseEventArgs<Control>(controlToAdd));
}
}
catch (Exception e)
{
handler(this, new ResponseEventArgs<Control>("[SP-Control]: Error while SaveControl. Saving the added control failed!", e));
}
}, null);
}
}
}
public abstract class ServiceAgentBase<T> : ServiceBase, IServiceAgentBase<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="ServiceAgentBase<T>"/> class.
/// </summary>
protected ServiceAgentBase() : base()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceAgentBase<T>"/> class.
/// </summary>
/// <param name="uri">service uri</param>
protected ServiceAgentBase(Uri uri) : base(uri)
{
}
/// <summary>
/// Attaches an entity to the service context
/// </summary>
/// <param name="entity">entity to attach</param>
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, "*");
}
/// <summary>
/// Deletes an entity
/// </summary>
/// <param name="entity">entity to delete</param>
public virtual void Delete(T entity)
{
this.Context.DeleteObject(entity);
}
/// <summary>
/// Updates an entity
/// </summary>
/// <param name="entity">entity to update</param>
public virtual void Update(T entity)
{
this.Context.UpdateObject(entity);
}
}
ServiceBase 中唯一值得注意的是我们创建了上下文并使用了 Json
this.Context.Format.UseJson();
如果我注释掉这一行并改用 Atompub,一切正常……你们中有人有同样的问题吗?有什么解决方案吗?
谢谢!
编辑:
提琴手的痕迹
JSON:
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...}
原子
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
<?xml version="1.0" encoding="utf-8"?><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">
<category term="Ria.DevelopmentModel.Control" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<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)" />
<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)" />
<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)" />
<id /><title /><updated>2013-09-18T09:20:07Z</updated><author><name /></author><content type="application/xml">
<m:properties><d:Accuracy m:type="Edm.Boolean">false</d:Accuracy><d:Activity m:null="true" /><d:ActualStatus m:type="Edm.Byte">0</d:ActualStatus><d:Automation m:type="Edm.Byte" m:null="true" /> ////All the other props....