>
Blog
Book
Portfolio
Search

3/10/2008

26611 Views // 0 Comments // Not Rated

Using ASP.NET AJAX 3.5 JSON Asynchronous Web Services

I have finally gotten around to playing with asynchronous ASP.NET AJAX JSON web services, and WHAT a beautiful thing they are! You can call a .NET web service asynchronously from the client, and play with a full object in JavaScript as the response all without a post back! And when I say a full object, I mean just that; my object had properties with primitive types, collections, and even other objects...all in JavaScript!

As usual with AJAX, the hardest part of using the technology is the configuration. But once you're past that it's easy, since we're really not doing anything new. You just call a method in your script client side, and write .NET code server side. So here's how to get started:

  • There are two ways to wire your script up. The first is via the web.config:

    Code Listing 1

    1. <asp:ScriptManager ID="ScriptManager1" runat="server">
    2. <Services>
    3. <asp:ServiceReference Path="WebService1.asmx" />
    4. </Services>
    5. </asp:ScriptManager>
  • Or, the second method, in code:

    Code Listing 2

    1. protected void Page_Load(object sender, EventArgs e)
    2. {
    3. if (!this.Page.IsPostBack)
    4. {
    5. ScriptManager sm = ScriptManager.GetCurrent(this.Page);
    6. if (sm == null)
    7. throw new Exception("No Script Manager found on page.");
    8. else
    9. {
    10. ServiceReference sr = new ServiceReference ("WebService1.asmx");
    11. if (!sm.Services.Contains(sr))
    12. sm.Services.Add(sr);
    13. }
    14. }
    15. }
  • Some might argue that you can dynamically add a Script Manager to the page in the case that there isn't one.  But, if I'm the author of a user control, that souldn't be my problem, so I'm going to leave that one alone.  Dynamic controls are messy enough; dynamic Script Managers...ugh...
  • Call your web service from a JavaScript method.
    • The call is to the fullly qualified web service method: <namespace>.<class>.<method>(<arguments>, <success callback method>, <fail callback method>, <params>).
    • The callback methods are other JavaScript methods that have a the following signature: <method name>(<web method return value>, <params>).
    • The <params> parameter is a way to pass values from the original JavaScript method to the callback that will actually be processing the web service's result.  A little trick I like to use is to pass an array as this parameter, filling it with normal variables, references to controls in the DOM, and/or other JSON objects.
    • If you don't want to use an error callback, pass a null for the third parameter.  If you don't need any parameters in your callback success method, you can just pass the first two arguments.
    • Here is an example of what you'll need in your script:

      Code Listing 3

      1. function CallMethod(someJSONObject, someContol, someValue)
      2. {
      3. var params = new Array();
      4. params[0] = someJSONObject;
      5. params[1] = someContol;
      6. params[2] = someValue;
      7. TestNamespace.TestService.TestMethod(someValue, Callback, null, params);
      8. }
      9. function Callback(result, params)
      10. {
      11. var someJSONObject = params[0];
      12. var someControl = params[1];
      13. var someValue = params[2];
      14. if (someJSONObject.SomeProperty == 'Some Constant')
      15. someContol.innerText = result;
      16. else
      17. someContol.innerText = someValue;
      18. }
    • And in your web service class, you'll have something like this:

      Code Listing 4

      1. using System;
      2. using System.Web.Services;
      3. using System.Web.Script.Services;
      4. namespace TestNamespace
      5. {
      6. [WebService(Namespace = "http://tempuri.org/")]
      7. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
      8. [ScriptService]
      9. public class TestService : WebService
      10. {
      11. [WebMethod]
      12. public SomeObject TestMethod(SomeObject x)
      13. {
      14. SomeObject y = x;
      15. ...
      16. return y;
      17. }
      18. }
      19. }

And there you have it! By registering the service with the page's Script Manager, your JavaScript will know what to do with the web service call. The best part about ASP.NET's implementation of this is that all of the JSON serialization and deserialization are abstracted to us. When you get that result back from the web service, you will have a full .NET object. I can't say that enough! Now of course, you'll only have access to public properties, (no methods or members) but we can now consume server objects from the client asynchronously with no postbacks!

Another bonus is speed. AJAX-enabling your UI improves user experience by not forcing them to watch a waving flag or a spinning green circle. However, it's all perception; nothing's actually faster. With JSON, you are not only circumventing all of the overhead involved in SOAP services, but also all the reflective mess involved with web service proxy classes. It is FAST.

Keep in mind, however, that there are some drawbacks. The main one is that this is not a replacement for Update Panels. This isn't as much a drawback as it is a reality check. It seems as though these web services cannot handle hardcore server processing as well as code-behind on a page can. I've seen random errors, including stack overflows, when calling recursive methods and doing other processor-intensive things behind a web method.

Although I feel that Update Panels are a poor-man's AJAX, that's not to say that they should be replaced across the board with JSON. If you want to do async postbacks, for example, wrapped around a GridView that does all kinds of server-side data binding to other parts of your page, then yeah, add four lines of HTML to your page (Update Panel and Content Template tags) and blow your user's minds! All I'm saying is this: don't think that you can completely do away with postbacks and offload all UI logic to the client; use discretion and only do it where it makes sense, and even then, use the appropriate method.

The next issue is the JSON max serialization length. Remember, behind the scenes, all JSON object are serialized and sent across the wire. There is a web.config AJAX setting that holds the maximum length of each string that contains the object. I've found if you're using beefy objects with dozens of properties and child collections, you'll exceed this length fairly quickly. I'm not sure if I feel this is a hack, but you can set your own value like so (or just blow it away, like I did):

Code Listing 5

  1. <system.web.extensions>
  2. <scripting>
  3. <webServices>
  4. <jsonSerialization maxJsonLength="999999" />
  5. /webServices>
  6. </scripting>
  7. </system.web.extensions>

The third issue is that your app and your JSON web services will not be able to communicate via standard session. Here's probably the only downfall to using .NET web services; they are (even more so than a page) stateless, and are designed only to "exist" during the scope of the current call. This is a bummer regardless, since the most common thing I've been doing with JSON is manipulating session objects from the client.

We can get around this by using the application object, since both the app and the web service are "in scope" here and can exchange information this way. Of course, keep in mind that all users' sessions share this same application object, so you'll need to key things off of guids and/or make sure to release these variables as soon as possible. I would recommend looking into the Cache object and setting expirations on your in-memory variables. Have fun!

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.


Loading...