5

我创建了一个 ASP.NET MVC 4 Web API 项目并通过 NuGet 安装了 Breeze,包括客户端示例,并且 ToDo 应用程序运行良好。我还有通过 Cordova 在 Android 平板电脑上调用 WebAPI 运行的应用程序,除了保存实体时,这也很有效。我已对 Global.asax ("Access-Control-Allow-Origin", "*") 进行了适当的更改以支持跨域操作。

当 Android 客户端调用它的 saveChanges() 时,数据实际上被保存到数据库中,但它的失败承诺总是在客户端上触发。

在 Web API 服务器上,我注意到通过浏览器进行 Breeze 调用时,我得到以下输出跟踪并成功保存:

iisexpress.exe Information: 0 : Operation=ODataActionFilter.ActionExecuting
iisexpress.exe Information: 0 : Message='Action returned 'Breeze.WebApi.SaveResult'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
iisexpress.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
iisexpress.exe Information: 0 : Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=ODataActionFilter.ActionExecuted, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=BreezeSampleController.ExecuteAsync, Status=200 (OK)
**iisexpress.exe Information: 0 : Response, Status=200 (OK), Method=POST, Url=http://localhost:59912/api/BreezeSample/SaveChanges, Message='Content-type='application/json; charset=utf-8', content-length=unknown'**
iisexpress.exe Information: 0 : Operation=JsonMediaTypeFormatter.WriteToStreamAsync
iisexpress.exe Information: 0 : Operation=BreezeSampleController.Dispose

但是,当从 Android 应用程序调用时,我会写入数据,但此跟踪出现错误:

iisexpress.exe Information: 0 : Message='Action returned 'Breeze.WebApi.SaveResult'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
iisexpress.exe Information: 0 : Message='Will use same 'XmlMediaTypeFormatter' formatter', Operation=XmlMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Selected formatter='XmlMediaTypeFormatter', content-type='application/xml; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
iisexpress.exe Information: 0 : Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=ODataActionFilter.ActionExecuted, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=BreezeSampleController.ExecuteAsync, Status=200 (OK)
**iisexpress.exe Information: 0 : Response, Status=200 (OK), Method=POST, Url=http://192.168.1.9:59912/api/BreezeSample/SaveChanges, Message='Content-type='application/xml; charset=utf-8', content-length=unknown'**
iisexpress.exe Error: 0 : Operation=XmlMediaTypeFormatter.WriteToStreamAsync, Exception=System.Runtime.Serialization.SerializationException: Type 'SMHMobileAPI.Models.BreezeSampleTodoItem' with data contract name 'BreezeSampleTodoItem:http://schemas.datacontract.org/2004/07/SMHMobileAPI.Models' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteArrayOfanyTypeToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
   at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteSaveResultToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph)
   at System.Net.Http.Formatting.XmlMediaTypeFormatter.<>c__DisplayClass7.<WriteToStreamAsync>b__6()
   at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)

除了一些序列化错误,我还注意到帖子标题“application/xml”。我不确定这是否相关,但如果有人可以提供帮助,我肯定需要一些帮助来尝试找到解决方案。

谢谢马克

4

1 回答 1

4

我很确定"application/xml" 相关的。

保存后,Breeze Web API 控制器将更新/添加的实体返回给您。您提到的“接受”标头会导致 Web API 尝试使用几乎总是失败的 XML 格式化程序格式化这些实体。

我不认为 Breeze 本身不会在 POST 上设置 Accept 标头(我不确定它是否在 GET 上设置了 Accept 标头)。

查看 IE10 中 jQuery AJAX 生成的请求表明 GET 的 Accept 标头是"application/json, text/javascript, */*; q=0.01". 对于 POST,Accept 和 Content-type 标头分别是"*\*""application/json"

您的 Android 流量中的 Accept 标头是什么?您没有指定将哪个标头设置为"application/xml"...但是由于这总是“错误的”,我认为这并不重要:)

您可以自定义 Breeze AJAX 适配器或完全按照此处所述替换它。你可以试试:

// 获取当前默认的 Breeze ajax 适配器
 var ajaxAdapter = 微风.core.config.getAdapterInstance("ajax");
 // 设置固定标题
 ajaxAdapter.defaultSettings = {
       标题:{
           “接受”:“应用程序/json,文本/javascript,*/*;q=0.01”
       },
};

这似乎在我对 IE10 和 Chrome 的测试中起到了作用。

我还将建议 Breeze Web API JsonFormatterAttribute 删除 XML 格式化程序给 tnat,我们知道它不适用于 Breeze 流量​​。

希望这有效。

于 2012-12-02T17:20:33.370 回答