1

I'm attempting to call a web service via AJAX in a WebForms application.

My script looks something like this:

$.post('UpdateServer.asmx/ProcessItem',
    'itemId=' + $(this).text(),
    function (result) {
        alert(result);
    });

My web service looks something like this.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class UpdateServer : System.Web.Services.WebService
{
    [WebMethod]
    public string ProcessItem(int itemId)
    {
        return new JavaScriptSerializer().Serialize(
            new { Success = true, Message = "Here I am!" });
    }
}

The web method is called as expected and with the expected argument. However, the argument passed to my success function (last parameter to $.post()) is of type document and does not contain the Success and Message members that I'm expecting.

What's are the magic words so that I can get back the object I'm expecting?

EDIT

On closer inspection, I can find the data I'm looking for as follows:

result.childNodes[0].childNodes[0].data: "{"Success":true,"Message":"Server successfully updated!"}"

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466

3 Answers3

2

The reason you're seeing that odd structure of nodes that end with JSON is because you're not calling the service the necessary way to coax JSON out of ASMX ScriptServices and then returning a JSON string anyway. So, the end result is that you're returning an XML document that contains a single value of that JSON string.

The two specific problems you're running into right now are that you're manually JSON serializing your return value and you're not calling the service with a Content-Type of application/json (.NET needs that to switch to JSON serializing the response).

Once you fixed those issues, you'd also run into an "invalid JSON primitive" error due to the data parameter being URL encoded instead of a valid JSON string.

To get it working, do this on the server-side:

[ScriptService]
public class UpdateServer : System.Web.Services.WebService
{
  [WebMethod]
  public object ProcessItem(int itemId)
  {
    return new { Success = true, Message = "Here I am!" };
  }
}

You could also create a data transfer object (aka ViewModel) to return instead of using an anonymous type and object, if you want.

To successfully get raw JSON out of that, do this on the client-side:

$.ajax({
  url: 'UpdateServer.asmx/ProcessItem',
  type: 'post',
  contentType: 'application/json',
  data: '{"itemId":' + $(this).text() + '}',
  success: function(result) {
    // This will be { d: { Success: true, Message: "Here I am!" } }.
    console.log(result);
  }
});

If you have a few minutes, read through the posts in the communication section of jQuery for the ASP.NET developer. You'll find a lot of that information helpful as you continue down this path.

Note: The links that helmus left were relevant. Nothing has fundamentally changed between 2.0 and present with regards to using ASMX ScriptServices to communicate via JSON. If you're interested in the truly cutting edge approach to this problem in .NET, ASP.NET Web API is the way to go.

Dave Ward
  • 59,815
  • 13
  • 117
  • 134
  • Thanks very much @Dave, I've been programming many, many years but am fairly new to these technologies. It seems that sometimes the `data` member should be in the `arg=value` format, and other times is should be in JSON as you have it. I am not finding consistencies here and, as you can see, other answers here did not work to clarify. Of course, your example is exactly right and works great. Clearly, I need to spend more time with this to better understand it. – Jonathan Wood Apr 16 '12 at 01:38
  • @JonathanWood: The reason you need to pass a JSON string here is because the `contentType` setting of `application/json` specifies that the incoming data will be in JSON format. Without that setting, URL encoded key=value pairs would be appropriate. However, ASP.NET will only respond with JSON if the *request* comes in as JSON also, so that's not an option here. – Dave Ward Apr 16 '12 at 13:13
0

Add this attribute to your ProcessItem method:

[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
Tuan
  • 5,382
  • 1
  • 22
  • 17
0

Be more explicit in your $.post call.

$.ajax({
    type:'post',
    url:'UpdateServer.asmx/ProcessItem',
    data: {'itemId':$(this).text()}
}).done(function (result) {
        alert(result);
});
000
  • 26,951
  • 10
  • 71
  • 101
  • Why are you recommending this? Do you feel there is a problem with $.post()? – Jonathan Wood Apr 15 '12 at 21:26
  • http://icewalker2g.wordpress.com/2011/05/08/avoid-jquery-post-or-jquery-get-if-possible-use-jquery-ajax-instead/ – 000 Apr 15 '12 at 21:28
  • Thanks. Maybe we are supposed to avoid $.post(). But the code above has a number of errors for me. Who would've thought this stuff would be so touchy!?! – Jonathan Wood Apr 15 '12 at 21:54