public override void CreateLayerAsync(Resource layerResource, SpatialReference mapSpatialReference, object userState)
        {
            if (layerResource.ResourceType == ResourceType.DatabaseTable)
            {
                featureService = new FeatureService(layerResource.Url);
                featureService.GetFeatureServiceDetailsFailed += (o, e) =>
                {
                    OnCreateLayerFailed(e);
                };
                featureService.GetFeatureServiceDetailsCompleted += (o, e) =>
                {
                    if (e.FeatureServiceInfo == null)
                    {
                        OnCreateLayerFailed(new ESRI.ArcGIS.Mapping.Core.ExceptionEventArgs(new Exception(Resources.Strings.ExceptionUnableToRetrieveLayerDetails), e.UserState));
                        return;
                    }
                    GeometryType GeometryType = GeometryType.Unknown;
                    switch (e.FeatureServiceInfo.GeometryType)
                    {
                        case "esriGeometryPoint":
                            GeometryType = GeometryType.Point;
                            break;
                        case "esriGeometryMultipoint":
                            GeometryType = GeometryType.MultiPoint;
                            break;
                        case "esriGeometryPolyline":
                            GeometryType = GeometryType.Polyline;
                            break;
                        case "esriGeometryPolygon":
                            GeometryType = GeometryType.Polygon;
                            break;
                    }
                    FeatureLayer newFeatureLayer = new FeatureLayer()
                    {
                        Url = featureService.Uri,
                        ID = Guid.NewGuid().ToString("N"),
                        Mode = FeatureLayer.QueryMode.OnDemand,
                        Renderer = new ESRI.ArcGIS.Mapping.Core.Symbols.HiddenRenderer()
                    };        
                    newFeatureLayer.SetValue(MapApplication.LayerNameProperty, layerResource.DisplayName);
                    newFeatureLayer.SetValue(Core.LayerExtensions.GeometryTypeProperty, GeometryType);
                    newFeatureLayer.SetValue(Core.LayerExtensions.DisplayUrlProperty, layerResource.Url);

                    if (e.FeatureServiceInfo.Fields != null)
                    {
                        Collection<FieldInfo> fields = new Collection<FieldInfo>();
                        foreach (Field field in e.FeatureServiceInfo.Fields)
                        {
                            if (field.DataType == "Microsoft.SqlServer.Types.SqlGeometry" || field.DataType == "esriFieldTypeGeometry")
                                continue;
                            fields.Add(new FieldInfo()
                            {
                                DisplayName = field.Name,
                                FieldType = mapFieldType(field.DataType),
                                Name = field.Name,
                                VisibleInAttributeDisplay = true,
                                VisibleOnMapTip = true,
                            });
                        }
                        newFeatureLayer.SetValue(Core.LayerExtensions.FieldsProperty, fields);
                    }
                    newFeatureLayer.OutFields.Add("*"); // Get all fields at configuration time
                    OnCreateLayerCompleted(new CreateLayerCompletedEventArgs() { Layer = newFeatureLayer, UserState = e.UserState, GeometryType = GeometryType });
                };
                featureService.GetFeatureServiceDetails(userState);
            }
            else
            {
                OnCreateLayerFailed(new ESRI.ArcGIS.Mapping.Core.ExceptionEventArgs(new Exception(string.Format(Resources.Strings.ExceptionCannotCreateLayerForResourceType, layerResource.ResourceType.ToString())), userState));
            }
        }
        private void processResult(ArcGISWebClient.DownloadStringCompletedEventArgs e) 
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                OnGetGroupLayerDetailsFailed(new ExceptionEventArgs(e.Error, e.UserState));
                return;
            }

            if (string.IsNullOrEmpty(e.Result))
            {
                OnGetGroupLayerDetailsFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionEmptyResponse), e.UserState));
                return;
            }

            LayerDetails layerDetails;
            try
            {
                string json = e.Result;
                Exception exception = Utils.CheckJsonForException(json);
                if (exception != null)
                {
                    OnGetGroupLayerDetailsFailed(new ExceptionEventArgs(exception, e.UserState));
                    return;
                }
                byte[] bytes = Encoding.Unicode.GetBytes(json);
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes))
                {
                    DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(LayerDetails));
                    layerDetails = dataContractJsonSerializer.ReadObject(memoryStream) as LayerDetails;
                    memoryStream.Close();
                }

                if (layerDetails == null)
                {
                    OnGetGroupLayerDetailsFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionUnableToDeserializeResponse), e.UserState));
                    return;
                }
            }
            catch (Exception ex)
            {
                OnGetGroupLayerDetailsFailed(new ExceptionEventArgs(ex, e.UserState));
                return;
            }

            List<Resource> childResources = new List<Resource>();
            if (layerDetails.SubLayers != null)
            {
                int totalSubLayerCount = layerDetails.SubLayers.Count;
                int subLayerCount = 0;                
                string parentMapServerUrl = Uri.Substring(0, Uri.IndexOf("MapServer", StringComparison.OrdinalIgnoreCase)+9);
                foreach (SubLayer subLayer in layerDetails.SubLayers)
                {       
                    // In order to determine whether a sub layer is a group layer or not, we need to make more requests
                    string subLayerUrl = string.Format("{0}/{1}", parentMapServerUrl, subLayer.ID);
                    Layer lyr = new Layer(subLayerUrl, ProxyUrl);
                    lyr.GetLayerDetailsFailed += (o, args) =>{

                        // Remove layer
                        childResources.Remove(args.UserState as Resource);

                        subLayerCount++;
                        if(subLayerCount >= totalSubLayerCount)
                            OnGetGroupLayerDetailsCompleted(new GetLayerDetailsCompletedEventArgs() { ChildResources = childResources, LayerDetails = layerDetails, UserState = e.UserState });
                    };
                    lyr.GetLayerDetailsCompleted += (o,args) =>{
                        subLayerCount++;
                        if (args.LayerDetails == null)
                        {
                            childResources.Remove(args.UserState as Resource);
                            return;
                        }

                        Resource childResource = args.UserState as Resource;
                        childResource.ResourceType = args.LayerDetails.Type == "Group Layer" ? ResourceType.GroupLayer : ResourceType.Layer;
                        childResource.DisplayName = args.LayerDetails.Name;
                        childResource.Url = string.Format("{0}/{1}", parentMapServerUrl, args.LayerDetails.ID);
                        childResource.ProxyUrl = ProxyUrl;
                        childResource.Tag = args.LayerDetails.ID;

                        if(subLayerCount >= totalSubLayerCount)
                            OnGetGroupLayerDetailsCompleted(new GetLayerDetailsCompletedEventArgs() { ChildResources = childResources, LayerDetails = layerDetails, UserState = e.UserState });
                    };

                    // Add layer before validating to preserve catalog order.  Layer will be removed if validation
                    // fails.
                    Resource child = new Resource();
                    childResources.Add(child);

                    lyr.GetLayerDetails(child);
                }
            }
            else
            {
                OnGetGroupLayerDetailsCompleted(new GetLayerDetailsCompletedEventArgs() { ChildResources = childResources, LayerDetails = layerDetails, UserState = e.UserState });
            }
        }
 public override bool IsResourceSelectable(Resource resource, Filter filter)
 {
     return resource.ResourceType == ResourceType.DatabaseTable;
 }
 public override bool SupportsChildResources(Resource resource, Filter filter)
 {
     bool hasChildResource = resource.ResourceType == ResourceType.Server
         || resource.ResourceType == ResourceType.Database;
     return hasChildResource;
 }
 private void getChildResourcesForServer(Resource parentResource, Filter filter, object userState)
 {
     server = new Server(parentResource.Url) { FilterForSpatialContent = (filter & Filter.SpatiallyEnabledResources) == Filter.SpatiallyEnabledResources };
     server.GetCatalogFailed += (o, e) =>
     {
         OnGetChildResourcesFailed(e);
     };
     server.GetCatalogCompleted += (o, e) =>
     {
         OnGetChildResourcesCompleted(new GetChildResourcesCompletedEventArgs() { ChildResources = e.ChildResources, UserState = e.UserState });
     };
     server.GetCatalog(userState);
 }
        public override Resource GetResource(string connectionString, string proxyUrl)
        {
            if (!connectionString.StartsWith("http://") && !connectionString.StartsWith("https://"))
                connectionString = string.Format("http://{0}", connectionString);

            // Initialize to "Server" so that "catalog" will be called with this value unless this logic detects that the
            // connection string actually refers to another type of resource like a map service, layer, etc.
            Resource res = new Resource()
            {
                Url = connectionString,
                ResourceType = ResourceType.Server,
            };

            try
            {
                Uri myUri = new Uri(connectionString);
                if (myUri.IsAbsoluteUri)
                {
                    string path = myUri.AbsolutePath;
                    string[] pathComponents = path.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);

                    if (pathComponents.Length >= 2)
                    {
                        // This is for SDS 10.1 which mimics ArcGIS Server
                        if (String.Compare(pathComponents[pathComponents.Length - 1], "featureserver", StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            res.ResourceType = ResourceType.FeatureServer;
                            res.DisplayName = pathComponents[pathComponents.Length - 2];
                            return res;
                        }
                        else if (String.Compare(pathComponents[pathComponents.Length - 2], "databases", StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            res.ResourceType = ResourceType.Database;
                            res.DisplayName = pathComponents[pathComponents.Length - 1];
                            return res;
                        }
                    }

                    if (pathComponents.Length >= 3)
                    {
                        if (String.Compare(pathComponents[pathComponents.Length - 2], "featureserver", StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            // It may seem wrong to call this a GP Server when the URL is clearly indicating a child tool, but
                            // we need to do this in order to get the parent service and all child tools since we want this
                            // context in the tree control.
                            res.ResourceType = ResourceType.FeatureServer;
                            res.DisplayName = pathComponents[pathComponents.Length - 3];

                            // Store the layer "id" in the tag. This will be extracted and used when populating the tree
                            // control in order to select the proper child item.
                            res.Tag = pathComponents[pathComponents.Length - 1];

                            // Create a URL that removes the trailing layer id
                            int i = res.Url.LastIndexOf("/");
                            if (i >= 0)
                                res.Url = res.Url.Remove(i);
                            return res;
                        }
                        else if (String.Compare(pathComponents[pathComponents.Length - 3], "databases", StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            // We need to do this in order to get the parent database and all child tables since we want this
                            // context in the tree control.
                            res.ResourceType = ResourceType.Database;
                            res.DisplayName = pathComponents[pathComponents.Length - 2];

                            // Store the layer "id" in the tag. This will be extracted and used when populating the tree
                            // control in order to select the proper child item.
                            res.Tag = pathComponents[pathComponents.Length - 1];

                            // Create a URL that removes the trailing layer id
                            int i = res.Url.LastIndexOf("/");
                            if (i >= 0)
                                res.Url = res.Url.Remove(i);
                            return res;
                        }
                    }
                }
            }
            catch
            {
            }

            // Parse to determine if this
            return res;
        }
 private void getFieldsInDatabaseTable(Resource parentResource, object userState)
 {
     featureServer = new FeatureService(parentResource.Url);
     featureServer.GetFeatureServiceDetailsFailed += (o, e) =>
     {
         OnGetChildResourcesFailed(e);
     };
     featureServer.GetFeatureServiceDetailsCompleted += (o, e) =>
     {
         OnGetChildResourcesCompleted(new GetChildResourcesCompletedEventArgs() { ChildResources = e.ChildResources, UserState = e.UserState });
     };
     featureServer.GetFeatureServiceDetails(userState);
 }
 private void getTablesInDatabase(Resource parentResource, object userState)
 {
     database = new Database(parentResource.Url);
     database.GetTablesInDatabaseFailed += (o, e) =>
     {
         OnGetChildResourcesFailed(e);
     };
     database.GetTablesInDatabaseCompleted += (o, e) =>
     {
         OnGetChildResourcesCompleted(new GetChildResourcesCompletedEventArgs() { ChildResources = e.ChildResources, UserState = e.UserState });
     };
     database.GetTables(userState);
 }
 public override void GetChildResourcesAsync(Resource parentResource, Filter filter, object userState)
 {
     if ((filter & Filter.None) == Filter.None ||
         (filter & Filter.SpatiallyEnabledResources) == Filter.SpatiallyEnabledResources ||
         (filter & Filter.FeatureServices) == Filter.FeatureServices)
     {
         switch (parentResource.ResourceType)
         {
             case ResourceType.Server:
             case ResourceType.FeatureServer:
                 getChildResourcesForServer(parentResource, filter, userState);
                 break;
             case ResourceType.Database:
                 getTablesInDatabase(parentResource, userState);
                 break;
             case ResourceType.DatabaseTable:
                 getFieldsInDatabaseTable(parentResource, userState);
                 break;
         }
     }
     else
     {
         OnGetChildResourcesCompleted(new GetChildResourcesCompletedEventArgs() { ChildResources = null, UserState = userState });
     }
 }
        private void processResult(ArcGISWebClient.DownloadStringCompletedEventArgs e) 
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(e.Error, e.UserState));
                return;
            }
            if (string.IsNullOrEmpty(e.Result))
            {
                OnGetCatalogFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionEmptyResponse), e.UserState));                                        
                return;
            }

            string json = e.Result;
            Exception exception = Utils.CheckJsonForException(json);
            if (exception != null)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(exception, e.UserState));
                return;
            }
            Catalog catalog = null;
            try
            {
                byte[] bytes = Encoding.Unicode.GetBytes(json);
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes))
                {
                    DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Catalog));
                    catalog = dataContractJsonSerializer.ReadObject(memoryStream) as Catalog;
                    memoryStream.Close();
                }
            }
            catch(Exception ex)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(ex, e.UserState));   
                return; 
            }

            if (catalog == null) 
            { 
                OnGetCatalogFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionUnableToDeserializeCatalog), e.UserState));   
                return; 
            }

            if (catalog.Folders == null && catalog.Services == null)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionNoServicesFoundOnServer), e.UserState));
                return; 
            }

            List<Resource> childResources = new List<Resource>();
            List<Resource> resources = Utility.GetResources(catalog, Filter, Uri, ProxyUrl, lockObj);
            int childCount = 0;
            int totalChildCount = resources != null ? resources.Count : 0;

            // If the catalog has any folders, add them to the returned list first
            if (catalog.Folders != null)
            {
                totalChildCount += catalog.Folders.Count;
                foreach (string folderName in catalog.Folders)
                {
                    Folder folder = new Folder(string.Format("{0}/{1}", Uri, folderName), ProxyUrl)
                    {
                        Filter = Filter,
                    };
                    folder.GetServicesInFolderFailed += (o, args) =>
                    {
                        // Remove the folder
                        lock (lockObj)
                        {
                            childResources.Remove(args.UserState as Resource);
                        }

                        childCount++;
                        if (childCount >= totalChildCount)
                            OnGetCatalogCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                    };
                    folder.GetServicesInFolderCompleted += (o, args) =>
                    {
                        int nestedChildTotalCount = args.ChildResources.Count();
                        if (nestedChildTotalCount == 0)
                        {
                            // Remove the folder
                            lock (lockObj)
                            {
                                childResources.Remove(args.UserState as Resource);
                            }
                        }

                        childCount++;
                        if (childCount >= totalChildCount)
                            OnGetCatalogCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                    };

                    // Add the folder before validation so that the catalog order is preserved.  Folder will be
                    // removed if found to be invalid.
                    Resource folderResource = new Resource()
                    {
                        DisplayName = folderName,
                        Url = string.Format("{0}/{1}", Uri, folderName),
                        ProxyUrl = ProxyUrl,
                        ResourceType = ResourceType.Folder,
                    };
                    lock (lockObj)
                    {
                        childResources.Add(folderResource);
                    }
                    folder.GetServices(folderResource);
                }
            }

            // Remove any undesired services due to filtering
            foreach (Resource childRes in resources)
            {
                IService childService = ServiceFactory.CreateService(childRes.ResourceType, childRes.Url, childRes.ProxyUrl);
                if (childService != null)
                {
                    // Determine if filtering requires detailed information about the server and only make async call to
                    // obtain detailed info if true.
                    if (childService.IsServiceInfoNeededToApplyThisFilter(Filter))
                    {
                        childService.ServiceDetailsDownloadFailed += (o, args) =>
                        {
                            // Remove resource
                            lock (lockObj)
                            {
                                childResources.Remove(args.UserState as Resource);
                            }

                            childCount++;
                            if (childCount >= totalChildCount)
                                OnGetCatalogCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                        };
                        childService.ServiceDetailsDownloadCompleted += (o, args) =>
                        {
                            IService service = o as IService;
                            if (service == null || !service.IsFilteredIn(Filter)) // check if service is filtered
                            {
                                // Remove resource
                                lock (lockObj)
                                {
                                    childResources.Remove(args.UserState as Resource);
                                }
                            }
                            childCount++;
                            if (childCount >= totalChildCount)
                                OnGetCatalogCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                        };

                        // Add the service before validation so that the catalog order is preserved.  Service will be
                        // removed if found to be invalid.
                        Resource childResource = new Resource()
                        {
                            DisplayName = childRes.DisplayName,
                            Url = childService.Uri,
                            ProxyUrl = ProxyUrl,
                            ResourceType = childService.Type
                        };
                        lock (lockObj)
                        {
                            childResources.Add(childResource);
                        }
                        childService.GetServiceDetails(childResource);
                    }
                    else
                    {
                        // Apply filtering using basic information, not detailed information
                        if (childService != null && childService.IsFilteredIn(Filter))
                        {
                            lock (lockObj)
                            {
                                childResources.Add(new Resource()
                                {
                                    DisplayName = childRes.DisplayName,
                                    Url = childService.Uri,
                                    ProxyUrl = ProxyUrl,
                                    ResourceType = childService.Type
                                });
                            }
                        }
                        ++childCount;
                    }
                }
            }

            if (childCount >= totalChildCount)
                OnGetCatalogCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
        }
        private void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                bool redownloadAttempted = WebClientFactory.RedownloadAttempted.Contains(webClient);
                if (Utils.IsMessageLimitExceededException(e.Error) && !redownloadAttempted)
                {
                    // Re-issue the request which should serve it out of cache      
                    // and helps us avoid the error which is caused by setting AllowReadStreamBuffering=false
                    // which was used to workaround the problem of SL4 and gzipped content
                    WebClientFactory.RedownloadStringAsync(webClient, finalUrl, e.UserState);
                }
                else
                {
                    if (redownloadAttempted) WebClientFactory.RedownloadAttempted.Remove(webClient);
                    OnGetCatalogFailed(new ExceptionEventArgs(e.Error, e.UserState));
                }
                return;
            }
            if (string.IsNullOrEmpty(e.Result))
            {
                OnGetCatalogFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionEmptyResponse), e.UserState));
                return;
            }

            string json = e.Result;
            Exception exception = Utils.CheckJsonForException(json);
            if (exception != null)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(exception, e.UserState));
                return;
            }
            DatabaseCatalog catalog = null;
            try
            {
                byte[] bytes = Encoding.Unicode.GetBytes(json);
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes))
                {
                    DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(DatabaseCatalog));
                    catalog = dataContractJsonSerializer.ReadObject(memoryStream) as DatabaseCatalog;
                    memoryStream.Close();
                }
            }
            catch (Exception ex)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(ex, e.UserState));
                return;
            }

            if (catalog == null)
            {
                OnGetCatalogFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionUnableToDeserializeCatalog), e.UserState));
                return;
            }

            List<Resource> childResources = new List<Resource>();            
            int totalDatabasesCount = catalog.Databases == null ? 0 : catalog.Databases.Count;
            if (catalog.Databases != null)
            {                
                int databaseCount = 0;
                foreach (string databaseName in catalog.Databases)
                {                    
                    Resource databaseResource = new Resource()
                    {
                        DisplayName = databaseName,
                        Url = string.Format("{0}/{1}", Uri, databaseName),
                        ResourceType = ResourceType.Database,
                    };
                    if (!FilterForSpatialContent)
                    {
                        childResources.Add(databaseResource);
                    }
                    else
                    {
                        Database db = new Database(databaseResource.Url) { FilterForSpatialContent = true };
                        db.GetTablesInDatabaseFailed += (o, args) => {
                            // remove the database
                            childResources.Remove(args.UserState as Resource);

                            databaseCount++;                            
                            if (databaseCount >= totalDatabasesCount)
                            {
                                // all done, raise the event
                                OnGetCatalogFailed(args);
                            }
                        };
                        db.GetTablesInDatabaseCompleted += (o, args) =>
                        {
                            databaseCount++;
                            bool hasAtleastOneSpatialTable = args.ChildResources.Count() > 0;
                            if (!hasAtleastOneSpatialTable)
                            {
                                // remove the database
                                childResources.Remove(args.UserState as Resource);
                            }
                            if (databaseCount >= totalDatabasesCount)
                            {
                                // all done, raise the event
                                OnGetCatalogRequestCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                            }
                        };

                        // Add database prior to validation to preserve catalog order.  Database will be removed
                        // if validation fails.
                        Resource child = new Resource()
                        {
                            DisplayName = databaseName,
                            Url = string.Format("{0}/{1}", Uri, databaseName),
                            ResourceType = ResourceType.Database,
                        };
                        childResources.Add(child);

                        db.GetTables(child);
                    }
                }                
            }

            if(!FilterForSpatialContent || totalDatabasesCount == 0)
            {
                OnGetCatalogRequestCompleted(new GetCatalogCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
            }
        }
        private void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                bool redownloadAttempted = WebClientFactory.RedownloadAttempted.Contains(webClient);
                if (Utils.IsMessageLimitExceededException(e.Error) && !redownloadAttempted)
                {
                    // Re-issue the request which should serve it out of cache      
                    // and helps us avoid the error which is caused by setting AllowReadStreamBuffering=false
                    // which was used to workaround the problem of SL4 and gzipped content
                    WebClientFactory.RedownloadStringAsync(webClient, finalUrl, e.UserState);
                }
                else
                {
                    if (redownloadAttempted) WebClientFactory.RedownloadAttempted.Remove(webClient);
                    OnGetTablesInDatabaseFailed(new ExceptionEventArgs(e.Error, e.UserState));
                }
                return;
            }
            if (string.IsNullOrEmpty(e.Result))
            {
                OnGetTablesInDatabaseFailed(new ExceptionEventArgs(new Exception("Empty response"), e.UserState));
                return;
            }

            DatabaseTables databaseTables = null;
            try
            {
                string json = e.Result;
                if (Utils.IsSDSCatalogResponse(json))
                {
                    // We were expecting a response consisting of tables, instead we got a response of the catalog
                    // this must be because we formed/guessed our URL wrong
                    OnGetTablesInDatabaseFailed(new ExceptionEventArgs(new Exception("Invalid response recieved. Catalog response recieved when expecting database tables"), e.UserState));
                    return;
                }
                Exception exception = Utils.CheckJsonForException(json);
                if (exception != null)
                {
                    OnGetTablesInDatabaseFailed(new ExceptionEventArgs(exception, e.UserState));
                    return;
                }
                byte[] bytes = Encoding.Unicode.GetBytes(json);
                using (MemoryStream memoryStream = new MemoryStream(bytes))
                {
                    DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(DatabaseTables));
                    databaseTables = dataContractJsonSerializer.ReadObject(memoryStream) as DatabaseTables;
                    memoryStream.Close();
                }

                if (databaseTables == null)
                {
                    OnGetTablesInDatabaseFailed(new ExceptionEventArgs(new Exception("Unable to deserialize response"), e.UserState));
                    return;
                }

                List<Resource> childResources = new List<Resource>();
                int totalTableCount = databaseTables.Tables != null ? databaseTables.Tables.Count : 0;                
                if (databaseTables.Tables != null)
                {
                    int tableCount = 0;
                    foreach (string table in databaseTables.Tables)
                    {                        
                        Resource databaseTable = new Resource()
                        {
                            ResourceType = ResourceType.DatabaseTable,
                            DisplayName = table,
                            Url = string.Format("{0}/{1}", Uri, table),
                        };
                        if (FilterForSpatialContent)
                        {
                            FeatureService featureService = new FeatureService(databaseTable.Url);
                            featureService.GetFeatureServiceDetailsFailed += (o, args) => {
                                // Remove the table
                                childResources.Remove(args.UserState as Resource);

                                tableCount++;
                                if (tableCount >= totalTableCount)
                                {
                                    // all done raise the event
                                    OnGetTablesInDatabaseFailed(args);
                                }
                            };
                            featureService.GetFeatureServiceDetailsCompleted += (o, args) =>
                            {
                                tableCount++;
                                if (args.FeatureServiceInfo == null
                                    || !args.FeatureServiceInfo.DoesTableHasGeometryColumn())
                                {       
                                    // Remove the table
                                    childResources.Remove(args.UserState as Resource);
                                }

                                if (tableCount >= totalTableCount)
                                {
                                    // all done raise the event
                                    OnGetTablesInDatabaseCompleted(new GetTablesInDatabaseCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                                }
                            };

                            // Add table before validation to preserve catalog order.  Table will be removed if
                            // validation fails.
                            Resource child = new Resource()
                            {
                                ResourceType = ResourceType.DatabaseTable,
                                DisplayName = databaseTable.DisplayName,
                                Url = databaseTable.Url,
                            };
                            childResources.Add(child);

                            featureService.GetFeatureServiceDetails(child);
                        }
                        else
                        {
                            childResources.Add(databaseTable);
                        }
                    }
                }

                if (!FilterForSpatialContent || totalTableCount == 0)
                {
                    OnGetTablesInDatabaseCompleted(new GetTablesInDatabaseCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                }
            }
            catch (Exception ex)
            {
                OnGetTablesInDatabaseFailed(new ExceptionEventArgs(ex, e.UserState));
            }
        }
        private void processResult(ArcGISWebClient.DownloadStringCompletedEventArgs e) 
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                OnGetServicesInFolderFailed(new ExceptionEventArgs(e.Error, e.UserState));
                return;
            }
            if (string.IsNullOrEmpty(e.Result))
            {
                OnGetServicesInFolderFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionEmptyResponse), e.UserState));
                return;
            }

            Catalog catalog = null;
            try
            {                
                string json = e.Result;
                byte[] bytes = Encoding.Unicode.GetBytes(json);
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes))
                {
                    DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Catalog));
                    catalog = dataContractJsonSerializer.ReadObject(memoryStream) as Catalog;
                    memoryStream.Close();
                }

                if (catalog == null)
                {
                    OnGetServicesInFolderFailed(new ExceptionEventArgs(new Exception(Resources.Strings.ExceptionUnableToDeserializeResponse), e.UserState));
                    return;
                }

                bool retrieveChildServices = (Filter & Filter.CachedResources) == Filter.CachedResources;
                List<Resource> resources = Utility.GetResources(catalog, Filter, Uri, ProxyUrl);
                if (retrieveChildServices && resources.Count > 0)
                {
                    int childCount = 0;
                    List<Resource> childResources = new List<Resource>();
                    foreach (Resource childResource in resources)
                    {
                        IService service = ServiceFactory.CreateService(childResource.ResourceType, childResource.Url, childResource.ProxyUrl);
                        if (service != null)
                        {
                            service.ServiceDetailsDownloadFailed += (o, args) =>
                            {
                                // Remove service
                                childResources.Remove(args.UserState as Resource);

                                childCount++;
                                if (childCount >= resources.Count)
                                    OnGetServicesInFolderCompleted(new GetServicesInFolderCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                            };
                            service.ServiceDetailsDownloadCompleted += (o, args) =>
                            {
                                childCount++;
                                IService ser = o as IService;
                                if (ser == null || !ser.IsFilteredIn(Filter))
                                {
                                    // Remove service
                                    childResources.Remove(args.UserState as Resource);
                                }
                                if (childCount >= resources.Count)
                                    OnGetServicesInFolderCompleted(new GetServicesInFolderCompletedEventArgs() { ChildResources = childResources, UserState = e.UserState });
                            };

                            // Add the service before validation so that the catalog order is preserved.  Service will be
                            // removed if found to be invalid.
                            Resource child = new Resource()
                            {
                                DisplayName = childResource.DisplayName,
                                Url = service.Uri,
                                ProxyUrl = ProxyUrl,
                                ResourceType = service.Type,
                            };
                            childResources.Add(child);

                            service.GetServiceDetails(child);
                        }
                    }
                }
                else
                {
                    OnGetServicesInFolderCompleted(new GetServicesInFolderCompletedEventArgs() { ChildResources = resources, UserState = e.UserState });
                }
            }
            catch(Exception ex)
            {
                OnGetServicesInFolderFailed(new ExceptionEventArgs(ex, e.UserState));
            }
        }