1

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 '&lt;&gt;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.&lt;WriteBufferedResponseContentAsync&gt;d__1b.MoveNext()</StackTrace></InnerException></Error>

EDIT: Clarified issue and added error response.

Samuel Davidson
  • 783
  • 6
  • 16
  • What about the request? What `Accepts` is supplied? – Lloyd Jul 27 '15 at 17:01
  • I misspoke in my question I will fix that. The Accept header in Chrome is " text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 " and in Fiddler I have tried just "application/xml " and both result in an error `500` – Samuel Davidson Jul 27 '15 at 17:03
  • I just realized my question is missing an important amount of information which is the error from the error code 500. I have fixed the question to be more descriptive. – Samuel Davidson Jul 27 '15 at 17:07
  • 1
    [This question](http://stackoverflow.com/questions/2404685/can-i-serialize-anonymous-types-as-xml) seems to indicate that there's no way to serialize anonymous types into XML out-of-the-box, and the answers seem to indicate that doing so is more trouble than it's worth. I'd probably stick with the "use a real class instead" comments. – Joe Enos Jul 27 '15 at 22:42

1 Answers1

1

In the stack trace there is following information:

Type'<>f__AnonymousType24[System.Int32,System.String,System.String,System.Collections.Generic.IEnumerable1[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.

lukbl
  • 1,763
  • 1
  • 9
  • 13