【发布时间】:2015-10-17 23:34:45
【问题描述】:
我的 API 控制器有两个动作,一个可以正常工作,并且会根据请求返回 JSON 或 XML。工作方式基本如下,返回一个IQueryable:
public IQueryable<UserDTO> GetUsers()
{
var users = db.Users.Select(user => new UserDTO()
{
Name = user.Name,
...
});
return users;
}
然后我有第二种方法,它返回一个匿名类型,它是User 的简化版本。因为它返回一个匿名类型,所以我在我构造的地方使用HttpResponseMessage 的返回类型。 JSON-only 方法如下:
public HttpResponseMessage GetSimplifiedUsers()
{
var users = db.Users.Select(user => new
{
Id = user.Id,
OtherIds = user.Others.Select(o=>o.Id),
...
});
return this.Request.CreateResponse(HttpStatusCode.OK,users);
}
为什么第二种方法只返回 JSON?我玩过 Fiddler 和 Chrome 并调整了 Accept 请求标头。如果请求 XML,则会出现错误 500,并出现以下错误:
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcZ2l0XGJvb3RjYW1wXExhYnNcTE1TIExhYlxMZWFybmluZ01hbmFnZW1lbnRTeXN0ZW1cTGVhcm5pbmdNYW5hZ2VtZW50U3lzdGVtXGFwaVx1c2Vyc1xzaW1wbGU=?=
X-Powered-By: ASP.NET
Date: Mon, 27 Jul 2015 17:06:26 GMT
Content-Length: 3894
<Error><Message>An error has occurred.</Message><ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.</ExceptionMessage><ExceptionType>System.InvalidOperationException</ExceptionType><StackTrace /><InnerException><Message>An error has occurred.</Message><ExceptionMessage>Type '<>f__AnonymousType2`4[System.Int32,System.String,System.String,System.Collections.Generic.IEnumerable`1[System.Int32]]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.</ExceptionMessage><ExceptionType>System.Runtime.Serialization.InvalidDataContractException</ExceptionType><StackTrace> at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContract(Int32 id, RuntimeTypeHandle typeHandle)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
at WriteArrayOf_x003C__x003E_f__AnonymousType2OfintstringstringArrayOfintNHLuklIfToXml(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.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.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()</StackTrace></InnerException></Error>
编辑:澄清问题并添加错误响应。
【问题讨论】:
-
请求呢?提供了什么
Accepts? -
我在我的问题中说错了,我会解决这个问题。 Chrome 中的 Accept 标头是“ text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8 ”,而在 Fiddler 中我只尝试过“ application/xml " 并且都导致错误
500 -
我刚刚意识到我的问题缺少大量重要信息,即错误代码 500 中的错误。我已将问题修复为更具描述性。
-
This question 似乎表明没有办法将匿名类型序列化为开箱即用的 XML,而答案似乎表明这样做麻烦多于其价值。我可能会坚持“改用真正的课程”cmets。