59

I'm wanting my WEB API method to return an XML object back to the calling application. Currently it's just returning the XML as a string object. Is this a no no? If so how do you tell the webapi get method that it's returning an object of type XML?

Thanks

Edit: An example of the Get method:

[AcceptVerbs("GET")]
public HttpResponseMessage Get(int tenantID, string dataType, string ActionName)
{
   List<string> SQLResult = MyWebSite_DataProvidor.DB.spReturnXMLData
            ("SELECT * FROM vwContactListing FOR XML AUTO, ELEMENTS").ToList();
   string AllResults = "";
   for (int i = 0; i < SQLResult.Count - 1; i++)
   {
       AllResults += SQLResult[i];
   }
    string sSyncData = "<?xml version=\"1.0\"?> " + AllResults;
    HttpResponseMessage response = new HttpResponseMessage();
    response.Content = new StringContent(sSyncData);
    return response;          
}

Its a bit hacky because im still at the prototyping stage. Will refactor when i can prove its doable.

SteveC
  • 15,808
  • 23
  • 102
  • 173
Matt
  • 3,305
  • 11
  • 54
  • 98

5 Answers5

115

If you don't want the controller to decide the return object type, you should set your method return type as System.Net.Http.HttpResponseMessage and use the below code to return the XML.

public HttpResponseMessage Authenticate()
{
  //process the request 
  .........

  string XML="<note><body>Message content</body></note>";
  return new HttpResponseMessage() 
  { 
    Content = new StringContent(XML, Encoding.UTF8, "application/xml") 
  };
}

This is the quickest way to always return XML from Web API.

SanyTiger
  • 666
  • 1
  • 8
  • 23
Arkadas Kilic
  • 2,416
  • 2
  • 20
  • 16
  • 21
    All too often people answer to be smart. I want answers to be simple and directly address the problem at hand. I have string with XML. I want to return XML. BINGO! Thanks for this answer. – Kevin May 08 '15 at 19:46
  • 2
    Side note: don't be like me and wonder why it isn't working when you're trying to return `Request.CreateResponse()` with your new `StringContent` object. Make sure you're returning a `new HttpResponseMessage()`. – A N May 10 '19 at 20:57
  • 3
    this is not working for me. I am getting this in the browser - any idea why??: StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Content-Type: application/xml; charset=utf-8 } – dan Jun 18 '19 at 23:17
  • Woo, after spending more than two weeks on different codes, I found this. God It saved my life. – skr Jun 30 '21 at 09:51
53

If you return a serializable object, WebAPI will automatically send JSON or XML based on the Accept header that your client sends.

If you return a string, you'll get a string.

Adam Baxter
  • 1,907
  • 21
  • 41
  • Hi all, The data the method is returning is dynamic. Situation A. is returning a list of entities. Situation B. could be a list of combination of 2 or more entities/classes. Im hoping to have it dynamic but fool the webapi into returning xml (if can also return JSON format than that would be cool, but XML is the primary neccessity) – Matt Jul 26 '12 at 04:20
  • Then create an object of some kind that can contain the data you want and return that. – Adam Baxter Jul 26 '12 at 04:35
  • 4
    Make sure you specify [Serializable()] on the object, I missed this one initially. – Christopher G. Lewis Jun 06 '13 at 14:04
31

Here's another way to be compatible with an IHttpActionResult return type. In this case I am asking it to use the XML Serializer(optional) instead of Data Contract serializer, I'm using return ResponseMessage( so that I get a return compatible with IHttpActionResult:

return ResponseMessage(new HttpResponseMessage(HttpStatusCode.OK)
       {
           Content = new ObjectContent<SomeType>(objectToSerialize, 
              new System.Net.Http.Formatting.XmlMediaTypeFormatter { 
                  UseXmlSerializer = true 
              })
       });
AaronLS
  • 37,329
  • 20
  • 143
  • 202
  • That is the way exactly what I was looking for. Thank you AaronLS – Shahdat Jan 28 '16 at 19:09
  • 1
    Great answer, thanks. Make sure `SomeType` has a default constructor, or you get an unhelpful error *"... configured formatter 'System.Web.Http.Tracing.Tracers.XmlMediaTypeFormatterTracer' cannot write an object of type ..."* – Dunc Mar 16 '16 at 09:53
  • 4
    You can just write `Content(System.Net.HttpStatusCode.OK, model, Configuration.Formatters.XmlFormatter)`. – Victor Ponamarev Apr 28 '16 at 23:57
22

You should simply return your object, and shouldn't be concerned about whether its XML or JSON. It is the client responsibility to request JSON or XML from the web api. For example, If you make a call using Internet explorer then the default format requested will be Json and the Web API will return Json. But if you make the request through google chrome, the default request format is XML and you will get XML back.

If you make a request using Fiddler then you can specify the Accept header to be either Json or XML.

Accept: application/xml

You may wanna see this article: Content Negotiation in ASP.NET MVC4 Web API Beta – Part 1

EDIT: based on your edited question with code:

Simple return list of string, instead of converting it to XML. try it using Fiddler.

public List<string> Get(int tenantID, string dataType, string ActionName)
    {
       List<string> SQLResult = MyWebSite_DataProvidor.DB.spReturnXMLData("SELECT * FROM vwContactListing FOR XML AUTO, ELEMENTS").ToList();
       return SQLResult;
     }

For example if your list is like:

List<string> list = new List<string>();
list.Add("Test1");
list.Add("Test2");
list.Add("Test3");
return list;

and you specify Accept: application/xml the output will be:

<ArrayOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <string>Test1</string>
  <string>Test2</string>
  <string>Test3</string>
</ArrayOfstring>

and if you specify 'Accept: application/json' in the request then the output will be:

[
  "Test1",
  "Test2",
  "Test3"
]

So let the client request the content type, instead of you sending the customized xml.

Habib
  • 219,104
  • 29
  • 407
  • 436
  • So currently I'm custom building the XML in the API get method as just pretty much a concatenated string and than returning that string. So nothing else has to be done past that? – Matt Jul 26 '12 at 03:58
  • @Raven, could you please post your method signature or part of related C# code in your question ? – Habib Jul 26 '12 at 04:24
  • Just added example to the post – Matt Jul 26 '12 at 04:31
  • the list returned from the stored proc isnt what I want to return. The stored proc returns a list when the returned XML generated from SQL Server is greater then so many characters. The list is just a chop up of the entire XML string returned from SQL Server. SO returning this as the object would be a problem. – Matt Jul 26 '12 at 05:00
  • I am not sure what you are trying to return, The point is that Web api shouldn't be concerned about whether XML or JSON is being returned, it should be the client responsiblity – Habib Jul 26 '12 at 05:07
  • You may create an container class for your return object and then simply return that class, the client will get xml or json based on the request – Habib Jul 26 '12 at 05:08
  • "and you specify Accept: application/xml the output will be: " unfortunately on the webapi controller I'm working on, even if I add this the headers in Postman, I _still_ get Json back. If I try AaronLS ' solution, I just get 500s with absolutely no error information despite Custom Errors being off in the web.config. –  Apr 27 '17 at 15:20
  • @Habib How to add this string at the beginning of the result. In original question he is trying to add this. I am able to return result based on accept header but I want to add this xml version tag. How to do it? – PSR Apr 17 '19 at 04:30
3

In my project with netcore 2.2 I use this code:

[HttpGet]
[Route( "something" )]
public IActionResult GetSomething()
{
    string payload = "Something";

    OkObjectResult result = Ok( payload );

    // currently result.Formatters is empty but we'd like to ensure it will be so in the future
    result.Formatters.Clear();

    // force response as xml
    result.Formatters.Add( new Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerOutputFormatter() );

    return result;
}

It forces only one action within a controller to return a xml without effect to other actions. Also this code doesn't contain neither HttpResponseMessage or StringContent or ObjectContent which are disposable objects and hence should be handled appropriately (it is especially a problem if you use any of code analyzers that reminds you about it).

Going further you could use a handy extension like this:

public static class ObjectResultExtensions
{
    public static T ForceResultAsXml<T>( this T result )
        where T : ObjectResult
    {
        result.Formatters.Clear();
        result.Formatters.Add( new Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerOutputFormatter() );

        return result;
    }
}

And your code will become like this:

[HttpGet]
[Route( "something" )]
public IActionResult GetSomething()
{
    string payload = "Something";

    return Ok( payload ).ForceResultAsXml();
}

In addition, this solution looks like an explicit and clean way to force return as xml and it is easy to add to your existent code.

P.S. I used fully-qualified name Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerOutputFormatter just to avoid ambiguity.

Alex Ilin
  • 51
  • 1
  • 4