Calling webservices from client-side Atlas: part 1 of 2

The March and May 2006 CTP’s of Atlas introduced two formal ways to call web services from a web browser. The difference is in the location of the web services.

  1. Local web services
  2. Remote or external web services

Atlas makes it really easy to call web services when they are local, i.e. reside in the same website as your Atlas-enabled web pages. You can create any ordinary .asmx web service and it will be callable from client-side JavaScript. Sure, you need to do some extra things, but there are no requirements to your service. Let’s take a look at how this works. Full source code is included at the end.

Say we have a web service GameQueryService.asmx whose class is defined like so:

[WebService(Namespace = “unr:www-killerapps-nl:services:games”)]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class GameQueryService : System.Web.Services.WebService

  [WebMethod]

  [XmlInclude(typeof(HalfLifeServerInfo))]

  [XmlInclude(typeof(SourceServerInfo))]

  public ServerInfo GetServerStatus(string serverAddress, int queryPort, GameEngine engine)

  {

    // Not relevant

  } 

}

We want to be able to call this web service from JavaScript. In an Atlas enabled .aspx page there is always a atlas:ScriptManager control present. You need to reference the web service from there.

<atlas:ScriptManager runat=serverID=atlasScriptManager>

  <Services>

    <atlas:ServiceReference Path=~/GameQueryService.asmx />

  </Services>

</atlas:ScriptManager>

<div id=”serverNameLabel”>Loading server information…</div>

Now, the scriptmanager will do loads of things for you. First of all, it will generate JavaScript code that represents a proxy to this very web service. It makes the service available through calls as simple as this:

GameQueryService.GetServerStatus(“213.132.174.125”, 27030, “HalfLife”, OnStatusComplete);

That is almost exactly like a regular C# call to a proxy generated by wsdl.exe or Add Web Reference. The first three arguments are the ones from the WebMethod. The last one is the name of a callback JavaScript method that gets called when the call has completed.
The magic behind the scenes is done by a different handler of .asmx requests. Web.config defines a new HttpHandler for .asmx and ties it to a ScriptHandlerFactory, allowing regular GET requests on the web service. GET requests are not supported by default in ASP.NET 2.0.

<httpHandlers>

  <remove verb=*path=*.asmx/>

  <add verb=*path=*.asmxtype=Microsoft.Web.Services.ScriptHandlerFactoryvalidate=false/>

  <add verb=*path=*.asbxtype=Microsoft.Web.Services.ScriptHandlerFactoryvalidate=false/>

In part 2 we will get to the .asbx extension.
You can switch off the ability to reach local web services from GET request, but this is enabled by default from the web.config

<microsoft.web>

  <webServices enableBrowserAccess=true/>

Let’s say we want to call this web service when the page loads. You might be tempted to use the onLoad event of the BODY tag to wait for the page to finish loading. You should not do this. There is a slight delay between the loading of the page and the generation of the JavaScript proxy. Instead you must trigger the call to the proxy via the Atlas application object:

<script type=text/xml-script>

  <page xmlns:script=http://schemas.microsoft.com/xml-script/2005>

    <components>

      <application load=OnLoad>

      </application>

    </components>

  </page>

</script>

The OnLoad method is called when the application has finished loading.

<script>

  function OnLoad(sender, eventArgs)

  {

    GameQueryService.GetServerStatus(“213.132.174.125”, 27030, “HalfLife”, OnStatusComplete);

  }

  function OnStatusComplete(result)

  {

    if (result == null)

    {

      alert(“No response received”);

      return;

    }

 

    alert(result.ServerName);

  }

</script>

The callback function expects a single parameter which is the result of the web service call, provided that no error or timeout has occured. In our case the result could be a null reference, so we need to test for that. But, if it is not, then you can access the result. We receive a ServerInfo (or one of its derived classes) object. The coolest thing is that you can access the properties of the result as if it were the actual C# object. That’s why you can access result.ServerName, because ServerName is one of the properties from the ServerInfo class.

You should also include a mechanism to catch timeouts and errors. For that, simply create a set of two JavaScript methods and pass the names of them as the last two arguments of the previous call to the proxy:

GameQueryService.GetServerStatus(“213.132.174.125”, 27030, “HalfLife”, OnStatusComplete, OnTimeout, OnError);

 

function OnError(result)

{

  alert(‘An error has occured. Details are listed below:n’ + result);

}

function OnTimeout(result)

{

  var serverNameLabel = new Sys.UI.Label($(‘serverNameLabel’));

  serverNameLabel.set_text(‘The gadget did not respond in time.’);

}

The OnTimeout method has another bit of client-side Atlas, manipulating the DIV with an ID of serverNameLabel through DHTML.

Calling your web service’s methods turns out to be not that complicated. Things change a little when you try to access a web service that is not in the same domain. We will cover bridging such calls in the next part.

File Attachment: LocalWebservicesAtlas.zip (425 KB)

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s