Saturday, November 29, 2008

ArcGIS Web ADF, JavaScript, and REST

Currently the Web ADF does not include an ArcGIS Server data source that supports consuming ArcGIS Server services via REST. Instead, the pre-packaged ArcGIS Server Internet data source uses the SOAP API to consume ArcGIS Server services. From a platform perspective, this makes sense because the Web ADF is founded in a rich, server-side ASP.NET development environment where SOAP provides some clear benefits. Let's look at this topic in more detail...

REST is a lightweight, non-standard format which can be used to request data over HTTP. REST is especially attractive to browser developers because it can be leveraged with JavaScript, JSON, and HTML to create an efficient, pure client solution - namely one that uses only browser logic and can initiate cross-domain requests for data. In general, requests contain a manually concatenated string of argument-value pairs and responses consist of standard content types, such as JSON (text) and images. While the benefits of using REST in a browser context with JavaScript are clear, other application environments present some hurdles. Since REST is not founded on a public standard, a developer needs documentation to learn how to interact with a REST service. This may suffice when working with client script, but developers working in an IDE with object-oriented languages like C#, VB.NET and Java often demand more. Why parse strings when you can work with explicit service types, discover parameters using intellisense, and utilize a proxy to manage requests\responses? This is where SOAP comes into the picture. SOAP is a standard W3C procotol which defines the XML message format for requests to and responses from a SOAP service. WSDL, another W3C standard language, provides the contract for how a consumer can interact with a SOAP service. While a SOAP message is an XML formatted string, a developer does not need to construct and parse it manually. Since SOAP is based on standard protocols and languages, toolkits for specific development environments are available to automatically construct native types. More specifically, the WSDL is used to construct a proxy class and a set of supporting types for use in an specific object-oriented environment. The proxy class exposes a set of operations (methods) which initiate Web requests. The supporting types are used to define inputs as value objects (termed 'value objects' because they only store values), which the proxy uses to construct a SOAP message. The response from a service can be deserialized by the proxy into one or more value objects. The benefit here is clear; a developer is able to use complex service-specific types native to their development environment to interact with a service.

The key difference between the use of REST and SOAP lies in the WSDL. The WSDL provides a central, language agnostic means for defining how to interact with a SOAP service. Different development environments can use the WSDL to construct the same set of types on-the-fly using a SOAP toolkit. REST does not define a compliment to the WSDL. As a result, documentation must be used to determine request and response content. Technically, you can manually construct a proxy and set of types to interact with a REST service, but without a central definition or standard (provided by a WSDL) the API structure will likely differ between developers.

So where does it make sense to leverage REST services in the Web ADF? REST services should be utilized in the browser, thus integrated with the Web ADF using the ADF JavaScript library. In this capacity, REST services may be used to enhance Web ADF application behavior and performance. One such area involves simply adding non-cached map services using pure client logic, something the Web ADF does not provide out-of-the-box. Currently non-cached map services use the AdfMapHandler class in ADF JavaScript to generate dynamic map images. This class requires Web-tier components; namely a map resource associated with a MapResourceManager and Map server control. It uses the ADF MapHandler to generate dynamic maps. The same applies for the Toc; it still relies heavily on Web-tier manipulation. You can, however, extend the ADF JavaScript DynamicLayer class to work with a non-cached service via REST.

The sample is available here.

There are a few caveats:

1) The layer (i.e. resource) is only available on the client; server components do not know about it. As a result, any requests to the server that work with map resources will not include this layer. In addition, most ADF controls require modification on the server to change their rendered content. This includes the Toc, so if you want the pure client layer to show up in an ADF Toc, you’ll need to customize Toc content using code on the server.

2) Using services secured with token-based authentication requires a proxy. Here’s a link to step on how to set this up: Using a proxy is a popular solution for working around cross-site scripting restrictions in a browser. Abe Fettig has researched a number of these solutions and presented them in a blog post. Note, you can use a proxy even if authentication is not required.

In the sample I provided, if a proxy (via the proxyUrl property) is defined when creating a new DynamicRestLayer, the proxy will be used. In this case, a POST request is always generated to guarantee that all the input arguments are passed to the remote site. The response is JSON and contains the properties of the generated map image, including the url and extent. If no proxy is specified for the DynamicRestLayer, a simple GET request for a map image is made via a dynamic image tag. The image tag source is not subject to cross-site scripting restrictions in the browser, so we don’t need a proxy. Both IE7 and FireFox 2+ work great with the no proxy solution. Unfortunately IE6 is somewhat problematic (e.g. triggers erroneous requests). If you need to support IE6, you may want to go the proxy route.

This brings up an interesting point - the ADF JavaScript Map component is designed to render and blend maps using dynamic image tags. The image tag source is not subject to cross-site scripting restrictions. Since a REST map service can return the raw map image, the sample included with this post merely builds on REST capabilities and ADF JavaScript architecture. Another option involves using dynamic script tags whose source references a REST endpoint that generates JSON. The data returned from the REST service is evaluated as a JavaScript object when the tag is loaded or inserted in the page. This could also work with ADF JavaScript, but would require more implementation code. Interestingly, dynamic script tags are leveraged by the ArcGIS JavaScript API.

Note, the sample also shows how to use REST to access tiles in a cached map service with a pure client layer. It may be of interest since the url is standard across sites (e.g. you don’t need to know the virtual cache directory).

Monday, November 10, 2008

Web ADF JavaScript: How to determine event argument contents

As many Web ADF developers already know, the 9.3 release contains a new public JavaScript library built on the Microsoft AJAX library. A host of ADF client controls and components (e.g. Map, Toolbar, etc.) maintain event handlers which enable ADF developers to listen for and interact with actions solely on the client (browser). Unfortunately the ADF JavaScript library reference does not contain the event argument types for event handlers. While this will be rectified at some point in the future, there is another option. You can determine the event argument types by looking in ADF JavaScript debug files installed in two locations:

  • <IIS Root>\aspnet_client\ESRI\WebADF\JavaScript
  • <ArcGIS Install>\DotNet\VirtualRootDir\aspnet_client\ESRI\WebADF\JavaScript
Search for references to this._raiseEvent in all debug JavaScript (*.debug.js) files. The first parameter to the _raiseEvent function is the type of event (e.g. 'click'). Any subsequent parameter is included as an event argument to any handler. You can look at the code to determine what the event argument contains.

For example, in the ESRI.ADF.UI.Map.debug.js file you’ll notice the click event is raised in the _onMouseUp function (shortened for the example):

_onMouseUp : function(evt) {
var e = this._makeMouseEventRelativeToMap(evt,true);
. . .

The browser event is modified in the _makeMouseEventRelativeToMap function to set its coordinate property to a new ESRI.ADF.Geometries.Point as the location of the user click on the map client control. In this case, the _raiseEvent function for 'click' indicates that an event argument is included, is modified, and the type is not an array. In other cases, no event argument is passed (e.g. map's extentChanging event) or the event argument contains an array with many objects (e.g. map’s extentChanged event).

The first parameter to an event handler is the sender, which is the client component on which the event was raised. Any subsequent argument, if defined, matches the event argument in the call to _raiseEvent.

Sunday, November 2, 2008

ArcGIS Server: Expose a custom server object extension via SOAP

Extending ArcGIS Server using ArcObjects can take two forms: a utility COM object or a server object extension. A utility COM object is simply a COM component created and managed explicitly in server context. A server object extension (SOE) is coupled with a server object and thus can share initialization, resource utilization, and disposal. Use of a COM utility has been possible since the first version of ArcGIS Server (9.0). Custom SOEs were introduced for ArcGIS Server .NET at version 9.2. ArcGIS Server Java does not offer an SOE solution at the moment, but it is likely forthcoming. The reasons for extending ArcGIS Server and differences between both techniques are available elsewhere so I'll skip that discussion here. I want to discuss exposing ArcObjects logic in a custom server object extension via a prepackaged ArcGIS Server Web service handler. Two major protocols are supported, SOAP and REST. Let's dive in...

The ArcGIS Server SOAP API is implemented at the server object level. This means that SOAP messages are processed directly by a server object or extension (SOE). The ArcGIS Server SOAP Web service handler directs SOAP messages to a server object for you. The ArcGIS Server REST API is not implemented at the server object level. The ArcGIS Server REST Web service handler processes restful requests and (in general) uses the ArcGIS Server SOAP API to communicate with ArcGIS Server. How does this relate to exposing a custom SOE as a Web service? The SOAP Web service handler contains logic to discover custom SOEs with a SOAP interface (see sample and discussion below). The REST Web service handler does not contain the logic to discover custom SOEs at this time. Consequently, to expose a custom SOE as a REST service you’ll need to create your own Web service to handle restful requests and work with the SOE. Unfortunately this means you'll need to work with ArcObjects remotely in the Web service logic, which will require an ArcGIS Server license in the app-tier... a less than optimal solution. The folks at ESRI who work on the REST handler may resolve this in the future.

I've included a sample that illustrates how to expose a custom SOE via the ArcGIS Server SOAP Web service handler. It builds on the current
Server SDK sample which shows how to create a simple SOE.

I’ve modified this sample to illustrate how to support exposing a custom SOE using an ArcGIS Server Web service endpoint. The sample is merely instructive, so it just provides the basics of custom SOE development. To expose a WSDL for the custom SOE and make it available via an ArcGIS Server Web service endpoint, create a WSDL and put it in the \XmlSchema folder on the machine where the SOM is running. The name of the registered server object extension and the name of the *.wsdl file must be the same. To process SOAP requests, implement the IRequestHandler and IRequestHandler2 interfaces in the custom SOE class. In this example, the implementation code parses the incoming SOAP request and generates a raw SOAP response string. The response should match the WSDL definition.

Download the sample here.

Everything is pretty raw and simple at the moment, but it works. I’m sure there’s a better way to create the WSDL and generate SOAP responses, but that’ll take some additional research. Once the custom SOE is deployed and enabled on a map service, you can use the following url to get the WSDL: http://localhost/arcgis/services/<service name>/MapServer/SimpleSOE_CSharp?wsdl

Wednesday, October 29, 2008

Inaugural Post

I thought it might be time to start posting a few diatribes on technologies I encounter and wrestle with on a regular basis. Hopefully this blog will introduce some interesting topics related to the mesh of ESRI server technologies, Microsoft products, platforms and components, and just about any other Web standard, protocol, format, API, etc.

Hope it works :)