I have a WebApi with several controllers which return different results. For example, one controller returned an IEnumberable, another a Bar, another an IEnumberable of IEnumberable etc., and all I had to do was:
return Ok(thething)
and everything worked fine, even complicated nested objects were serialized with no problem.
Now, The client asked that all results be returned in a Wrapper:
public class Wrapper
{
public bool Success { get; set; }
public int ErrorCode { get; set; }
public String ErrorMessage { get; set; }
public String Referer { get; set; }
public Object Payload { get; set; }
}
Thought it would be trivial, but when I try to return it from the controller:
return Ok( new Wrapper { Success=true, Referer="me", Payload=thething)
I get a serialization error.
The Exception message is:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
The Inner Exception message is:
Type 'System.Linq.Enumerable+WhereSelectListIterator
2[[EPiServer.Find.Api.SearchHit
1[[DGTNext.Api.Data.Entities.ProductSummary, DGTNext.Api.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], EPiServer.Find, Version=9.6.0.3185, Culture=neutral, PublicKeyToken=8fe83dea738b45b7],[DGTNext.Api.Data.Entities.ProductSummary, DGTNext.Api.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' with data contract name 'ArrayOfProductSummary:http://schemas.datacontract.org/2004/07/DGTNext.Api.Data.Entities' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer 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 the serializer.
What am I doing wrong? Why did the Ok()
function seem to be handle any object before, but has problems now?
Thanks.
Edit: As requested, a simple example of something causing the error:
class Foo {
public int AnInt { get; set; }
}
public IHttpActionResult Get() {
return Ok(new Wrapper { Success=true, Referer="me", Payload= new Foo {AnInt = 7}});
}
Edit:
Well, I came up with kind of a solution, but it still raises some questions.
I made my Wrapper generic in the type of the Payload.
public class Wrapper<T>
{
public bool Success { get; set; }
public int ErrorCode { get; set; }
public String ErrorMessage { get; set; }
public String Referer { get; set; }
public T Payload { get; set; }
}
So now, this works:
public IHttpActionResult Get() {
List<Foo> foos = new List<Foo>();
foos.Add(new Foo { AnInt = 7 });
foos.Add(new Foo { AnInt = 8 });
return Ok(new Wrapper<IEnumerable<Foo>> { Success=true, Referer="me", Payload= foos});
}
It returns:
{"Success":true,"ErrorCode":0,"ErrorMessage":null,"Referer":"me","Payload":[{"AnInt":7},{"AnInt":8}]}
And my "real" call:
public IHttpActionResult Get() {
IEnumerable<ProductSummary> prods = db.getProductSummaries(shopId, culture, queryParams, paging);
return Ok(new Wrapper<IEnumerable<ProductSummary>> { Success = true, Referer = "me", Payload = prods });
}
returns:
<WrapperOfArrayOfProductSummaryzc2y5_Pnl>
<ErrorCode>0</ErrorCode>
<ErrorMessage i:nil="true"/>
<Payload>
<d2p1:ProductSummary>
<d2p1:Culture i:nil="true"/>
<d2p1:Guid i:nil="true"/>
<d2p1:Id>2</d2p1:Id>
<d2p1:Name>Letto Asia</d2p1:Name>
<d2p1:ambient>
<d2p1:Id>1073741838</d2p1:Id>
<d2p1:Name>notte</d2p1:Name>
</d2p1:ambient>
etc.
So not bad, but this raises two questions:
To test the webapi, I'm calling it by putting an URL in the Firefox address bar and looking an the results in the browser. Why in the world does the first call return Json, and the second XML? As far as I know I'm just using default everything.
Why is the XML now adding that namespace to all the element names? Can I prevent this? When I was just returning the same thing without the wrapper, this didn't happen.