ASP.NET WebService is Wrapping my JSON response with XML tags
Asked Answered
W

6

13

I'm not sure where I'm going wrong of what I'm missing.

I'm building an ASP.NET 2.0 (on the .Net 3.5 framework) Web application and I am including a webservice. Note that this is not an MVC project. I wish to expose a method which will return a JSON string; formatted to feed the jqGrid jQuery plugin.

This is the preliminary test method I've implemented in my service: thanks to (Phil Haack's Guide for MVC)

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string getData()
{
    JavaScriptSerializer ser = new JavaScriptSerializer();

    var jsonData = new
    {
        total = 1, // we'll implement later 
        page = 1,
        records = 3, // implement later 
        rows = new[]{
          new {id = 1, cell = new[] {"1", "-7", "Is this a good question?", "yay"}},
          new {id = 2, cell = new[] {"2", "15", "Is this a blatant ripoff?", "yay"}},
          new {id = 3, cell = new[] {"3", "23", "Why is the sky blue?", "yay"}}
        }
    };

    return ser.Serialize(jsonData); //products.ToString();
}

When invoked this is returning (formatted for clarity):

<?xml version="1.0" encoding="utf-8" ?> 
<string  mlns="http://tempuri.org/">
{
  "total":1,
  "page":1,
  "records":3,
  "rows":
    [
      {"id":1,"cell":["1","-7","Is this a good question?","yay"]},
      {"id":2,"cell":["2","15","Is this a blatant ripoff?","yay"]},
      {"id":3,"cell":["3","23","Why is the sky blue?","yay"]}
    ]
}
</string> 

How would I achieve the above response without the xml wrappings?

Welltodo answered 13/1, 2010 at 16:39 Comment(0)
T
10

Three things you may not be doing:

  • Marking the method static
  • Performing a POST
  • Hand an empty "{ }" for the data in jQuery.

There may be a way to call the method with a GET, I've only ever used POST. I was able to get your example working with this:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script>
    // In your javascript block
    $(document).ready(function()
    {
        $.ajax({
            url: "/Default.aspx/Tester",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: "{}",
            success: done
        });
    });

    function done(data)
    {
        // Include http://www.json.org/json2.js if your browser doesn't support JSON natively
        var data = JSON.parse(data.d);
        alert(data.total);
    }
</script>

The code behind (you don't need to create a webservice, you can put this in your default.aspx):

[WebMethod]
public static string Tester()
{
    JavaScriptSerializer ser = new JavaScriptSerializer();

    var jsonData = new
    {
        total = 1, // we'll implement later 
        page = 1,
        records = 3, // implement later 
        rows = new[]{
              new {id = 1, cell = new[] {"1", "-7", "Is this a good question?", "yay"}},
              new {id = 2, cell = new[] {"2", "15", "Is this a blatant ripoff?", "yay"}},
              new {id = 3, cell = new[] {"3", "23", "Why is the sky blue?", "yay"}}
            }
        };

    return ser.Serialize(jsonData); //products.ToString();
}

The result:

{"d":"{\"total\":1,\"page\":1,\"records\":3,\"rows\":[{\"id\":1,\"cell\":[\"1\",\"-7\",\"Is this a good question?\",\"yay\"]},{\"id\":2,\"cell\":[\"2\",\"15\",\"Is this a blatant ripoff?\",\"yay\"]},{\"id\":3,\"cell\":[\"3\",\"23\",\"Why is the sky blue?\",\"yay\"]}]}"}

A more detailed explanation is here

Tasty answered 13/1, 2010 at 17:22 Comment(4)
How did you get your result. When I implement as you have I seem to only get "[object Object]" back. This could be naivety to JSON, but I can't seem to get it to work.Welltodo
I used firebug in Firefox to view the response from the Net panel - click the response tab for that request.Tasty
Do you know why the data is being wrapped in the variable "d"?Welltodo
The "d" isn't added by jQuery but .NET 3.5 as a security measure.Tasty
D
11

In your code, don't "return" the json. Use instead:

Context.Response.Write(ser.Serialize(jsonData));

Then you'll be good.

The regular return command helps you by putting in a more proper service format. Some would say it'd be better form to use this, and unwrap your json on the client from this format. I say, just spit down the stuff exactly how you want to use it!

Davedaveda answered 13/1, 2010 at 16:53 Comment(3)
This seems to work if you navigate to the .aspx page then follow the linkage through to invoke. Unfortunately if I try to navigate to "GridDataRequest.asmx/getData" I get a yellow screen of death "Request format is unrecognized for URL unexpectedly ending in '/getData'."Welltodo
+1 for this handy gem of code. I've however chosen another solution to better-fit with our model.Welltodo
Yep, better to use json.parse, as long as you're using jquery anyway. More proper.Davedaveda
T
10

Three things you may not be doing:

  • Marking the method static
  • Performing a POST
  • Hand an empty "{ }" for the data in jQuery.

There may be a way to call the method with a GET, I've only ever used POST. I was able to get your example working with this:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script>
    // In your javascript block
    $(document).ready(function()
    {
        $.ajax({
            url: "/Default.aspx/Tester",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: "{}",
            success: done
        });
    });

    function done(data)
    {
        // Include http://www.json.org/json2.js if your browser doesn't support JSON natively
        var data = JSON.parse(data.d);
        alert(data.total);
    }
</script>

The code behind (you don't need to create a webservice, you can put this in your default.aspx):

[WebMethod]
public static string Tester()
{
    JavaScriptSerializer ser = new JavaScriptSerializer();

    var jsonData = new
    {
        total = 1, // we'll implement later 
        page = 1,
        records = 3, // implement later 
        rows = new[]{
              new {id = 1, cell = new[] {"1", "-7", "Is this a good question?", "yay"}},
              new {id = 2, cell = new[] {"2", "15", "Is this a blatant ripoff?", "yay"}},
              new {id = 3, cell = new[] {"3", "23", "Why is the sky blue?", "yay"}}
            }
        };

    return ser.Serialize(jsonData); //products.ToString();
}

The result:

{"d":"{\"total\":1,\"page\":1,\"records\":3,\"rows\":[{\"id\":1,\"cell\":[\"1\",\"-7\",\"Is this a good question?\",\"yay\"]},{\"id\":2,\"cell\":[\"2\",\"15\",\"Is this a blatant ripoff?\",\"yay\"]},{\"id\":3,\"cell\":[\"3\",\"23\",\"Why is the sky blue?\",\"yay\"]}]}"}

A more detailed explanation is here

Tasty answered 13/1, 2010 at 17:22 Comment(4)
How did you get your result. When I implement as you have I seem to only get "[object Object]" back. This could be naivety to JSON, but I can't seem to get it to work.Welltodo
I used firebug in Firefox to view the response from the Net panel - click the response tab for that request.Tasty
Do you know why the data is being wrapped in the variable "d"?Welltodo
The "d" isn't added by jQuery but .NET 3.5 as a security measure.Tasty
D
3
  1. turn the return type to void
  2. put your object onto ^_^
[WebMethod]
public static void GetDocuments()
{
    HttpContext.Current.Response.ContentType = "application/json";
    HttpContext.Current.Response.Write(JsonConvert.SerializeObject( ^_^ ));
    HttpContext.Current.Response.End();
}
Danielldaniella answered 16/5, 2019 at 11:48 Comment(0)
E
2

When you mark the service as a ScriptService, it automatically handles the JSON serialization. You shouldn't manually serialize the response. See this stack overflow entry for more detail.

Electronarcosis answered 13/1, 2010 at 16:56 Comment(1)
Correct. Unless you want to use a different serialiser such as Newtonsoft its far better to let asmx work as designed - and that includes handling the serialisation for you. The key to not getting XML in the response is to ensure that IIS knows that JSON is required. Then just return the C# object and the serialisation to JSON happens automatically: https://mcmap.net/q/122328/-asmx-web-service-how-to-return-json-and-not-xmlAlkmaar
V
2

I've had better luck with doing the following:

[WebMethod]
public static void GetDocuments()
{
    HttpContext.Current.Response.ContentType = "application/json";
    HttpContext.Current.Response.Write(JsonConvert.SerializeObject(repository.GetDocuments()));
    HttpContext.Current.Response.End();
}

It's important to set the content type properly, and to write the JSON directly to the respond, then to end the response so that no further data is sent to corrupt your response. An advantage of this architecture is you can use whatever serializer you want, you're not limited to the built in JSON serializer. In this case, I used Json.NET.

I realize that this is abusing the architecture (and I personally dislike having a void return type for something that's supposed to return data) but this is the only truly reliable method I've found.

On the other hand, you should be switching to WCF or Web API, for reasons John Saunders describes here. Web API in particular is very easy to use, and allows for content type negotiation between the client and server.

Vanderbilt answered 17/11, 2014 at 15:2 Comment(0)
A
1

If you request JSON, and if you include the [ScriptService] attribute, ASP.NET will automatically serialise the response to JSON. That you were seeing XML suggests one of these 2 preconditions were not being met. The suggestions to serialise to JSON manually are wrong, unless you wish to use a different serialiser such as Newtonsoft.

Here is a simple working example of a JSON enabled ASMX web service:

<%@ WebService Language="C#" Class="WebService" %>
using System;
using System.Collections.Generic;
using System.Web.Services;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {
    [WebMethod]
    public MyClass Example()
    {
        return new MyClass();
    }

    public class MyClass
    {
        public string Message { get { return "Hi"; } }
        public int Number { get { return 123; } }
        public List<string> List { get { return new List<string> { "Item1", "Item2", "Item3" }; } }
    }
}

JavaScript to request it and process the response (we'll simply pop up a JS alert with the message from MyClass.Message) :

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test</title>
    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.4.js" type="text/javascript"></script>  
</head>
<body>
    <script type="text/javascript">
        $.ajax({
            type: "POST",
            url: "WebService.asmx/Example",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: "{ }",
            error: function (XMLHttpRequest, textStatus, errorThrown) { alert(langError + " " + textStatus); },
            success: function (msg) {
                alert(msg.d.Message);
            }
        });
    </script>
</body>
</html>

Http request:

POST http://HOST.com/WebService.asmx/Example HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://HOST.com/Test.aspx
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Connection: Keep-Alive
Content-Length: 3
Host: HOST.com

{ }

HTTP response:

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 08 Oct 2013 08:36:12 GMT
Content-Length: 98

{"d":{"__type":"WebService+MyClass","Message":"Hi","Number":123,"List":["Item1","Item2","Item3"]}}

Result:

"Hi" is displayed in a JS popup.

See also:

https://mcmap.net/q/122328/-asmx-web-service-how-to-return-json-and-not-xml

https://mcmap.net/q/279798/-how-to-not-serialize-the-__type-property-on-json-objects

Alkmaar answered 8/10, 2013 at 8:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.