Reputation: 791
My API controller has two actions, one works properly and will return either JSON or XML depending on the request. The working method is basically the following and returns an IQueryable
:
public IQueryable<UserDTO> GetUsers()
{
var users = db.Users.Select(user => new UserDTO()
{
Name = user.Name,
...
});
return users;
}
Then I have a second method that returns an anonymous type that is a simplified version of the User
. Since it returns an anonymous type I use a return type of HttpResponseMessage
where I construct. The JSON-only method is the following:
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);
}
Why is this second method only returning JSON? I have played around with Fiddler and Chrome and adjusting the Accept
request headers. If XML is requested there is an error 500
with the following error:
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>
EDIT: Clarified issue and added error response.
Upvotes: 1
Views: 403
Reputation: 1773
In the stack trace there is following information:
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.
So it looks like you cannot serialize collection of annonymous classes.
Try creating dedicated class for response or use UserDTO
if it is applicable in your new method.
Upvotes: 1