46

I try to get the output XML or JSON data based on my input. I used the below WEB API code but not able to exact output.

public string Get(int id)
{
    if (GlobalConfiguration.Configuration.Formatters.XmlFormatter == null)
    {
        GlobalConfiguration.Configuration.Formatters.Add(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
    }
    if (GlobalConfiguration.Configuration.Formatters.JsonFormatter == null)
    {
        GlobalConfiguration.Configuration.Formatters.Add(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
    }
    if (id == 1)
    {
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);                
        GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;                
    }
    else
    {
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
    }
    return "value";
}

7 Answers 7

82

Add the below code app_start event in global.asax file. In API Url add the query string:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
    new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));

GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
    new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));

e.g.:

for xml : http://localhost:49533/api/?type=xml

for json: http://localhost:49533/api/?type=json
Sign up to request clarification or add additional context in comments.

2 Comments

here is a tip if you need to use Route instead of QueryString, I created a custom mapper by inheriting from "MediaTypeMapping" and overriding "TryMatchMediaType"
Does it work with HTTP routing like [Route( "api/{type}/entity" )] ?
10

What you are trying to do will not work in a multi-threaded environment. You cannot add to and remove from the formatters collection on a per-request basis. Here is a better way of accomplishing what you want.

public HttpResponseMessage Get(int id)
{
    Foo foo = new Foo();
    var content = new ObjectContent<Foo>(foo,
                    ((id == 1) ? Configuration.Formatters.XmlFormatter :
                                Configuration.Formatters.JsonFormatter));
    return new HttpResponseMessage()
    {
         Content = content
    };
}

1 Comment

Ah I see this is similar to the answer I found, nice
8

Looked into this a bit more, and found your answer in another post:

public HttpResponseMessage Get(int id)
{
    string content = "value";

    if (id == 1)
    {
        return Request.CreateResponse<string>(HttpStatusCode.OK, content, Configuration.Formatters.JsonFormatter);
    }

    return Request.CreateResponse<string>(HttpStatusCode.OK, content, Configuration.Formatters.XmlFormatter);
}

2 Comments

Now that actually does look useful!
@Kirkaiya I noticed Badri's answer afterwards, they're doing the same thing it seems, but this seems to make a lot more sense to me :) Thanks!
6

It also works to force the accept headers. Great option if you aren't always returning HttpResponseMessage's. I.e

Request.Headers.Add("Accept", "text/json");
return Request.CreateResponse(HttpStatusCode.OK, yourobject);

or

Request.Headers.Add("Accept", "application/xml");
return new Rss20FeedFormatter(feed);

1 Comment

Can the Request.Headers.Add piece be added at the controller level
5

If your request specifies the mime type, for example application/json, then web api will format the response appropriately.

If you are attempting to debug your web api manually, use a tool like Fiddler 2 to specify the type.

This article describes the concept.

2 Comments

+1 I would suggest to do this as well, rather than a custom input on a query string, as it is the standard way to do it
4

QueryStringMapping` is nice solution but I need a default value for type.

for xml : localhost:49533/api/?type=xml

for json: localhost:49533/api/

I solve that situation like that:

GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
var jSettings = new JsonSerializerSettings();

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", new MediaTypeHeaderValue("application/xml")));

1 Comment

Add the code to the App_Start/WebApiConfig.cs file.
3

While the accepted answer by vijayjan15 seems the best way to go for your specific situation (that is, using the MediaTypeMappings), you could alternatively have two different methods, one that returns XML and one that returns JSON. To do that, you can instantiate a controller-specific HttpConfiguration (to avoid modifying the one in GlobalConfiguration.Configuration):

public MyReturnType GetMyTypeAsXml() {
    Configuration = new HttpConfiguration();
    Configuration.Formatters.Clear();
    Configuration.Formatters.Add(new XmlMediaTypeFormatter());

    return new MyReturnType();
}

public MyReturnType GetMyTypeAsJson() {
    Configuration = new HttpConfiguration();
    Configuration.Formatters.Clear();
    Configuration.Formatters.Add(new JsonMediaTypeFormatter());

    return new MyReturnType();
}

I'm not sure how much overhead there is in spinning up a new instance of HttpConfiguration (I suspect not a lot), but the new instance comes with the Formatters collection filled by default, which is why you have to clear it right after instantiating it. Note that it if you don't use Configuration = new HttpConfiguration(), and instead modify Configuration directly, it modifies the GlobalConfiguration.Configuration property (so, it would impact all your other WebApi methods - bad!).

2 Comments

My proposed alternate answer was based on the assumption that the question author either didn't have access to the request itself (eg, to modify the headers) or wanted to specify XML or JSON if the request originated in a browser (in which case, different browsers send different accept headers, so that FireFox will show XML, while IE will pull as JSON - if he wants to be explicit, he can't rely on the headers). ;-)
Yeah true, I was presuming he had control of the request with the check on id == 1 but I guess he was just trying it out in a sample project first, so good point :) I added an answer, think I found the best way of doing this in another SO post.

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.