Corey Coogan

Python, .Net, C#, ASP.NET MVC, Architecture and Design

  • Subscribe

  • Archives

  • Blog Stats

    • 109,869 hits
  • Meta

Posts Tagged ‘json’

Calling ASP.NET Web Service (ASMX) from JQuery

Posted by coreycoogan on December 17, 2010


UPDATE: 12/17/2010 12:55 AM CST – Thanks to Dave’s comments below, I learned that the script service handles object serialization to JSON for me. This means that if your return type is that of an object, it will automatically serialize this object to JSON. If you want to create an anonymous object, such as you may do from a LINQ query, just set your return type to “object”. I thought I had to turn that into a string, but that’s not necessary. Thanks again Dave. I also removed the [ScriptMethod] attribute, which is isn’t necessary and actually causes the JSON returned to be a string and not a JSON object.

I’ve not done anything real meaningful in Web Forms in some time, so I was very surprised at how much trouble I had trying to call a simple HelloWorld service from a jQuery Post and have it return some JSON back to my screen.  It took a couple hours to finally get it right, and I know I’m not the only one.  There are Stack Overflow posts about this and many blog posts as well. Unfortunately, as helpful as those posts were, it seems that I was still missing things… the things I’m going to cover in this here post.

ASMX Web Service

First, let’s start with the old school web service that I’d like to use to communicate with the client.  Sure I could go WCF, but an ASMX is just fine for my needs and darn simple. The important things to note on the service:

  • To call a service from JavaScript, the service class must be decorated with the [ScriptService] attribute.
  • The service method should not decorated with the [ScriptMethod] attribute, only the [WebMethod] attribute. The ScriptMethod causes the return JSON to be a string that needs to be deserialized on the client. Without it, it comes down as a valid JSON object, automatically deserialized by jQuery for me.
  • If you are going to return a hardcoded JSON string for jQuery to parse, it has be formated with double quotes around the names and properties.  I was using single ticks, which I have gotten away with in some cases, but not here (return “{\”response\”:\”Hello World\”}”).
  • Mark the return type of the method to “object” if you want to return with an anonymous object from a LINQ query or something like that. 

This is an example of a working service:

    [ScriptService]
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class HelloWorld : System.Web.Services.WebService
    {
        [WebMethod]
        //[ScriptMethod(ResponseFormat = ResponseFormat.Json)] Don't need this attribute.  
        public HelloWorldResponse SayIt(string name)
        {
            //the Identity of the logged in user is available
            var userName = HttpContext.Current.User.Identity.Name;
            
           return new HelloWorldResponse() {Name = name, NickName = "Mad Dog"};
        }

        public class HelloWorldResponse
        {
            public string Name { get; set; }
            public string NickName { get; set; }
        }
    }

AJAX and jQuery

Now for the jQuery, for which I’m using version 1.4.4.  Here’s the things that tripped me up:

  • I was using a JQ $.post call in my web pages to communicate with the server.  That caused me some problems in that the data was always returned as XML, no matter what I tried.  Knowing that $.post is a shortcut against the $.ajax method, I switched to using that so I could explicitly set the contentType to “application/json”.  I do realize that I can probably set that on the $.post method, as I’m pretty sure I’ve done that in the past, but that can cause confusion, especially with new developers.
  • If you are accessing more than one service in more than place, create a utility method or use the $.ajaxSetup method to configure the defaults.
  • If you don’t set the dataType to “json”, the response data is returned as xml.
  • If you don’t pass empty data when there are no parameters needed for the service, the response data will be returned as xml.
  • The dictionary passed to the service in the data parameter must be quoted or the service will throw a 500 error.  Web Service parameters are passed with the name of the parameter as the key (see example).
  • This is discovered soon enough, but the response from the service comes wrapped in another JSON object, available at the ‘d’ key.  If the value for ‘d’ is a JSON string, it will have to be deserialized into a proper JSON object.  I use jQuery’s $.parseJSON function for that. This example will return ‘d’ as a proper JSON object.
<script>
    $(document).ready(function() {

        //this would be done in a common script file if you are going to
        //make a lot of these calls
        $.ajaxSetup({ type: 'POST', dataType: 'json', contentType: 'application/json', data: {} });

        $('#btn').click(function() { 
             //call the web service with the button is clicked
            $.ajax({ url: 'webservices/helloworld.asmx/SayIt',
                data: '{ "name": "Corey" }', //ensure the data is enclosed in a quote
                success: function(data) {
                    var responseJson = data.d; //the real json is wrapped, get it and parse it
                    $('#sayit').html(responseJson.Name + ' aka ' + responseJson.NickName); //put the response value from the return json
                }
            });

            //return false to avoid a postback
            return false;
        });

    });
</script>
<div>
	<button id='btn'>Load It</button>
	<div id='sayit'></div>
</div>

Authorization and Authentication

Any ASMX service written in our web project will be available to the world.  If you are using a ROLES and MEMBERSHIP provider and your site requires authentication, use the <location> tag in your web.config to lock down the directory where you put all your services.  In my example, I’ve put all my services in a WebServices directory and only authenticated users in the Admins role have access.

 <location path="WebServices">
    <system.web>
      <authorization>
        <deny users="?"/>
        <allow roles="Admins"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

If the user is logged in, there will be an active IIdentity in HttpContext.Current.User.Identity, so your service can use that for authorization where necessary.

var userName = HttpContext.Current.User.Identity.Name;

Posted in Ajax, ASP.NET, jQuery | Tagged: , , , , , | 9 Comments »