2

I have a WebApi with several controllers which return different results. For example, one controller returned an IEnumerable<Foo>, another a Bar, another an IEnumerable of IEnumerable 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 Referrer { 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, Referrer = "me", Payload = thething)

I get a serialization error:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.

The inner exception message is:

'System.Linq.Enumerable+WhereSelectListIterator2[[EPiServer.Find.Api.SearchHit1[[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, Referrer = "me", Payload = new Foo { AnInt = 7 } });
}

Edit #2: 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 Referrer { 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, Referrer = "me", Payload = foos });
}

It returns:

{
    "Success": true,
    "ErrorCode": 0,
    "ErrorMessage": null,
    "Referrer": "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, Referrer = "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:

  1. 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.

  2. 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.

8
  • Can you amend your question with an example of the object that you're passing in Payload? Commented Jun 16, 2016 at 15:37
  • Does this realy compile: return Ok( new Wrapper { Success=true, Referer="me", Payload=thething), You missed } at the end. should be like this:. return Ok( new Wrapper { Success=true, Referer="me", Payload=thething}); Commented Jun 16, 2016 at 17:32
  • Yes, it compiles, copy-paste error. Commented Jun 18, 2016 at 7:15
  • Do you want JSON or XML? Commented Jun 18, 2016 at 12:54
  • As I understand it, one of the advantages to using the WebApi framework is that it will return whatever the caller asks for. @TomasLycken Commented Jun 26, 2016 at 17:37

1 Answer 1

5

Add this code to global.asax below on Application_Start:

Update from .Ignore to .Serialize. It must work.

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

or you may look at this answer

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.