This walk-through shows how to get information about services available on an ArcGIS Server instance. If you know the URL of the ArcGIS Server machine, it is possible to obtain a list of services. You can also obtain information about an individual service, such as its layers and spatial extent. This information could be used to build an application that dynamically finds and uses a service, rather than having the service be hard-coded in the application. Remember you can get information about services with the Services Directory. Use the approach shown here only if you need to work programmatically with services in your application.

This walk-through parallels closely the example "Discovering map services" in the Interactive SDK. The complete code for the walk-through is at the bottom of this page if you have any questions about where code goes during the steps below.

Getting information about map services

This walk-through displays a list of map services that are available on a designated server. The application does not display any map, and therefore does not use the Virtual Earth map. Of course, the approach here could be combined with a VE map to display and use map services.

You will see references to several helper functions as we go through the walk-through. We will provide the code for these helper functions shortly after referring to them initially. We use the code in these functions more than once, so it makes sense to put them in separate functions.

  1. Create a new web page with a basic outline. Do not start with the VE map page as in other walk-throughs. In this page, include the reference to the ArcGIS JavaScript extension. You may use a page like the following:
    CopyBasic HTML page
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>Discovering Map Services</title>
        <script src="http://serverapi.arcgisonline.com/jsapi/ve/?v=1.4" type="text/javascript"></script>
    </head>
    <body>
        <form id="form1" action="">
        </form>    
    </body>
    </html>
    Save the file, for example to ArcGISVEMapServices1.htm.
  2. Inside the <form> of the body, add a drop-down (select) list that shows the URLs to one or more servers. You may use the URLs shown in the sample code below. After the list, add a button to get the map services with an onclick event function. Then add a <div> that will display the map services information.
    CopySome global variables
    Rest Endpoint URL:  
    <select id="serviceUrl" >
        <option>http://serverapi.arcgisonline.com/arcgis/rest/services</option>
        <option>http://maps.arcgisonline.com/rest</option> 
    <select>
    <input id="Button1" type="button" value="Get Map Services" onmousedown="GetResourceInfo()" />
    <div id="ResourceInfoDisplay" style="font-family: Verdana; font-size: x-small; width: 700px; 
        height: 375px; overflow: auto; border: solid 1px black;"></div>
  3. In the <head> of the page, add a <script> section. In the script section, add these global variables that we will need in multiple functions:
    CopyAdding global variables
    <script language="javascript" type="text/javascript" >
        var folderCount = 0;
        var totalFolders = 0;
        var folders = null;
        var servicesText = ""; 
        var serviceUrl = "";
    
    </script>
  4. Inside the script block after the variables, add the function that handles the onclick of the Button added earlier. In this function, first clear out the contents of the ResourceInfoDisplay <div> we added earlier, in case the user previously retrieved services information. Also reset the servicesText to an empty string (we'll store text about services here). Then get the URL that the user has selected from the drop-down list. Create an ArcGISLayerFactory, and use it to send a GetResourceInfo request, which will return information about the map services. As with other requests, the first argument is the URL of the service, and the second is the function that will receive the response. We'll create that function in the next step.
    CopyButton handler - initiates server request
    function GetResourceInfo() {
        document.getElementById("ResourceInfoDisplay").innerHTML = "";
        servicesText= ""; 
        var f = document.forms[0];
        serviceUrl = f.serviceUrl.options[f.serviceUrl.selectedIndex].text;
        var agisve_services = new ESRI.ArcGIS.VE.ArcGISLayerFactory();
        agisve_services.GetResourceInfo(serviceUrl, showResourceInfo); 
    }
  5. Next, add the showResourceInfo function that will receive the response from the server. This function takes two arguments; if the second is null, the first will have the data we need (see the Discussion for details on this point), so add a line that gets whichever has the data. Next, add a call to a function (addServicesInfo) that will process the information about the map services. We will code this function in the next step.

    The response from the initial request contains services only for the root folder of the server. If we want to get services within folders, we must do additional work. To do this, in the function, get a reference to the folders, set the totalFolders to the number of folders, and initialize the folderCount index to zero. Then, if any folders exist, request the information about the first folder. We must do this by constructing the URL to folder, which is simply the folder name appended to the the service URL. We send the request using a helper function, restRequest, that we will code shortly. We send this helper function the folder URL and the name of yet another function that will receive the response to function requests, getFolderInfo, which we'll create below. Finally, if the server has no folders at all, just display the response, using another function(!), showAll. That makes four functions to code--we'll work on those next.

    CopyHandling the initial services response
    function showResourceInfo(sender, data) {
        var resourceInfo = (data!=null) ? data : sender;            
        addServicesInfo(resourceInfo.services);
    
        folders = resourceInfo.folders;
        totalFolders = folders.length; 
        folderCount = 0;
    
        if (totalFolders>0) {
            var url = serviceUrl + "/" + folders[0];
            restRequest(url, getFolderInfo);  
        } else 
            showAll(); 
    }
  6. Let's create the addServicesInfo function next. We called this in the previous step to process the information about the services in the server's root. This function receives an array of services. Loop through this array and record the names and URLs of map services. You can do this by checking the service's .type, which is "MapServer" for map services. Add to the servicesText variable the service's name, type, and URL.
    CopyProcessing the root services
    function addServicesInfo(serviceArray) {
        for (var i=0;i<serviceArray.length;i++) { 
            var service = serviceArray[i];
            if (service.type=="MapServer")
                servicesText += "<b>" + service.name + "</b> (" + service.type + ")"
                   + "  URL: "  + serviceUrl + "/" + service.name + "";
        }
    }
    As you'll see, we reuse this function to process the services within folders.
  7. Next, add the restRequest function. This function uses the RestRequest class to send a request to the server. We must send the folder-information request directly to the server using this approach. Use the RestRequest's Send method to send the folder's URL and the name of the function that will receive the folder information response. Remember we called this function above and passed it the callback function getFolderInfo, which we'll code next.
    CopySending a REST request
    restRequest = function(url, callback) {
        var request = new ESRI.ArcGIS.VE.RestRequest();
        request.Send(url, callback);
        return false;   
    }
  8. The response from the folder request goes to the getFolderInfo function, which we now add. As with the showResourceInfo function that handled the root's services, check the input arguments for the data set. Then call the addServicesInfo function that we created earlier, passing it the list of services in the data. This records the names of the services. For services in folders the name includes the name of the folder.

    After the first folder is processed, we need to request the next folder. We can process successive folders by calling the getFolderInfo function recursively. Do this by incrementing the folderCount index, then checking whether we've reached the end of the folder list (totalFolders). If not, then use the restRequest function we created earlier to send the next request. Pass restRequest the name of the next folder, available from the folders array. If we've reached the last folder, then just call the showAll function to display the results.

    CopyProcessing a folder
    function getFolderInfo(sender, data) {
        if (data==null) data = sender;
        addServicesInfo(data.services);
    
        folderCount++;
        if (folderCount<totalFolders) {
            var url = serviceUrl + "/" + folders[folderCount]; 
            restRequest(url, getFolderInfo);   
        } else 
            showAll(); 
    }
  9. Finally, add the showAll function to display the map services. If none were found, then set the servicesText variable to that effect. Otherwise, set the innerHTML of the ResourceInfoDisplay div to the servicesText value.
    CopyDisplaying services results
    function showAll() {
        if (servicesText.length==0) servicesText = "No Map Services found."
        document.getElementById("ResourceInfoDisplay").innerHTML += 
            "<b>Available Map Services:</b><br /><br />" + servicesText;            
    }
  10. Save the page, and open it in a browser. It should display the drop-down list with services, a button, and an empty display box. Choose a server URL from the drop-down list and click Display Map Services. After a moment, the map services available in the server should be listed. Services within folders will include the folder name.

Discussion

As we saw in the walk-though, services can be organized into folders. Information can be obtained about one folder at a time, so each folder requires a separate request to the server. This makes obtaining complete information about a server slightly more complex, because we must iterate through the folders.

In step 5 of the walk-through, we saw that the event handler function (showResourceInfo) takes two arguments, but the second may be null. The reason we use this approach is because events may pass a response to their handlers with either one or two arguments. An older style passed two arguments: a reference to the sender, plus the data for the response. A newer style passes only one argument, the response data. The approach we used will work with either approach, since if the second argument is null, we know the first one has the appropriate response data.

If you are interested in obtaining information about an individual map service, see the example "Getting layer information from a Map Service" in the Interactive SDK. That sample simply prints the JSON-formatted data for the map service. You can also process the returned data for the map service to examine its properties, such as layers, fullExtent, spatialReference and documentInfo. If you want detailed information about an individual layer, for example to obtain the attribute fields of the layer, you can send a separate REST request using the URL of the layer. The URL will be that of the map service, plus the ID of the layer. For example, for a map service with URL http://example.com/arcgis/rest/services/MapService1, the information about layer with ID 1 would be available from http://example.com/arcgis/rest/services/MapService1/1. This same information is available through the Services Directory, but the preceding information is useful if you need to discover map services dynamically in your application.

This example does not display any map services that are secured and require a login. If the server has secured services and you wish to display them, you will need to provide credentials. This is done either with a token or via a Windows login. For details, see Working with secure ArcGIS services.

Complete code for this walkthrough

CopyExample: Getting information about map services
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Discovering Map Services</title>
    <script src="http://serverapi.arcgisonline.com/jsapi/ve/?v=1.4" type="text/javascript"></script>
    <script language="javascript" type="text/javascript" >
        var folderCount = 0;
        var totalFolders = 0;
        var folders = null;
        var servicesText = ""; 
        var serviceUrl = "";

        function GetResourceInfo() {
            document.getElementById("ResourceInfoDisplay").innerHTML = "";
            servicesText= ""; 
            var f = document.forms[0];
            serviceUrl = f.serviceUrl.options[f.serviceUrl.selectedIndex].text;
            var agisve_services = new ESRI.ArcGIS.VE.ArcGISLayerFactory();
            agisve_services.GetResourceInfo(serviceUrl, showResourceInfo); 
        }

        function showResourceInfo(sender, data) {
            var resourceInfo = (data!=null) ? data : sender;            
            addServicesInfo(resourceInfo.services);

            folders = resourceInfo.folders;
            totalFolders = folders.length; 
            folderCount = 0;

            if (totalFolders>0) {
                var url = serviceUrl + "/" + folders[0];
                restRequest(url, getFolderInfo);  
            } else 
                showAll(); 
        }

        function getFolderInfo(sender, data) {
            if (data==null) data = sender;
            addServicesInfo(data.services);

            folderCount++;
            if (folderCount<totalFolders) {
                var url = serviceUrl + "/" + folders[folderCount]; 
                restRequest(url, getFolderInfo);   
            } else 
                showAll(); 
        }

        function addServicesInfo(serviceArray) {
            for (var i=0;i<serviceArray.length;i++) { 
                var service = serviceArray[i];
                if (service.type=="MapServer")
                    servicesText += "<b>" + service.name + "</b> (" + service.type + ")<br/>"
                       + "  URL: "  + serviceUrl + "/" + service.name + "<br />";
            }
        }

        function showAll() {
            if (servicesText.length==0) servicesText = "No Map Services found."
            document.getElementById("ResourceInfoDisplay").innerHTML += 
                "<b>Available Map Services:</b><br /><br />" + servicesText;            
        }

        restRequest = function(url, callback) {
            var request = new ESRI.ArcGIS.VE.RestRequest();
            request.Send(url, callback);
            return false;   
        }
    </script>
</head>
<body>
    <form id="form1" action="">
        Rest Endpoint URL:  
        <select id="serviceUrl" >
            <option >http://serverapi.arcgisonline.com/arcgis/rest/services</option>
            <option >http://maps.arcgisonline.com/rest</option> 
       </select>
        <input id="Button1" type="button" value="Get Map Services" onmousedown="GetResourceInfo()" />
        <div id="ResourceInfoDisplay" style="font-family: Verdana; font-size: x-small; width: 700px; 
            height: 375px; overflow: auto; border: solid 1px black;"></div>        
    </form>
</body>
</html>