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

Part 1 left us able to call web services that are local. In part 2 we will take a look at web services that are remote to our own website that hosts the Atlas enabled page. Seems like a trivial thing to do. I mean, it’s “just” a soap call over HTTP, right? The challenge lies in the fact that the MSXML2.XmlHttp COM object is not allowed to make cross-domain HTTP requests. The solution is to bridge your call through the local website. The hosting web server will make the call on your behalf to the remote web service. The mechanism that Atlas brings is the .asbx bridge file. A bridge file defines what the remote web service looks like.

<?xml version=1.0 encoding=utf-8 ?>

<bridge namespace=KillerApps.Games.Atlas className=GameServerStatus>

  <proxy type=KillerApps.Games.Atlas.GameQueryService, App_Code
   
serviceUrl=”http://localhost:1256/WebSite/GameQueryService.asmx” />

  <method name=GetServerStatus>

    <input>

      <parameter name=serverAddress />

      <parameter name=queryPort />

      <parameter name=engine />

    </input>

  </method>

  <method name=GetPlayers>

    <input>

      <parameter name=serverAddress />

      <parameter name=queryPort />

      <parameter name=engine />

    </input>

  </method>

</bridge>

The XML fragment above defines a proxy to the remote service located at the endpoint http://localhost:8442/WebSite/GameQueryService.asmx. Although the web service might define more operations two of those are mentioned and are callable by the proxy. The input and (optional) output parameters are listed as well. The proxy is a server-side class that you must provide. I used a wsdl.exe generated proxy class and included it in the App_Code folder of the Website that also hosts the .asbx file.:

wsdl.exe /language:C# /out:GameQueryServiceProxy.cs /namespace:KillerApps.Games.Atlas http://localhost:1256/Website/GameQueryService.asmx

In the first part you already saw how the ScriptHandlerFactory class handles all requests for .asmx (local web services) and .asbx (bridge files to remote web services). To be able to call a remote service, simply list the location of the .asbx file instead of local .asmx file you saw before.

<atlas:ScriptManager runat=”server” ID=”scriptManager”>

  <Services>

    <atlas:ServiceReference Path=”~/GameQueryService.asbx />

  </Services>

</atlas:ScriptManager>

Like before, the ScriptManager will emit JavaScript for the bridge containing an object that acts as a JavaScript proxy to the local server, which in turn bridges the call to the remote web service. The JavaScript is inserted by adding a include to the same location as the .asbx file, plus an extra /js, as in: http://localhost/GameQueryService.asbx/js. The resulting JavaScript for the bridge file above is:

Type.registerNamespace(‘KillerApps.Games.Atlas’); KillerApps.Games.Atlas.GameServerStatus=new function() { this.appPath = “http://localhost:8442/WebSite/&#8221;; var cm=Sys.Net.ServiceMethod.createProxyMethod; cm(this,”GetServerStatus”,”args”); cm(this,”GetPlayers”,”args”); cm(this,”__invokeBridge”,”method”,”args”); }

You can call the web service through the JavaScript object that has a “namespace” and “className” as indicated in the bridge file. The method names correspond to the defined methods. The call to the service looks like this:

function OnLoad(sender, eventArgs)

{

  KillerApps.Games.Atlas.GameServerStatus.GetServerStatus

    ( { “serverAddress” : “213.132.174.125”,

        “queryPort” : 27030,

        “engine” : “HalfLife” },

      OnStatusComplete);

}

Notice that the bolded part is a different way to pass all parameters to the proxy. For proxies corresponding to local web services the arguments were “as always”. Now you need to define your arguments in a new Javascript dictionary. The syntax is { “parameterName1” : “argumentValue1”, “parameterName2” : “argumentValue2”, … }. After the arguments you can still provide a callback methodname, plus one for timeouts and one for errors.

You probably noticed that the service endpoint was a local address, that served as a remote web service for testing purposes. As soon as you want to access an actual remotely located web service, you will run into security problems. The bridge won’t let you call into cross-domain methods that are not marked safe. You do so by adding an extra attribute to each method that you consider safe (e.g. which transport non-confidential information, or the ones that cannot be misused)

<method name=GetServerStatus safeForCrossDomain=true>

This should get your web method calls to work. There is some mention of marking your web method calls as a WebOperation, like so:

[WebOperation(true, ResponseFormatMode.Json, true)]

[WebMethod]

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

but I haven’t found a situation yet where this is actually necessary to do.

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