/// <summary>
        /// Gets the service information for an ArcGIS Server service.
        /// </summary>
        /// <param name="url">The URL of the service</param>
        /// <param name="userState">Object to be passed to the callback</param>
        /// <param name="callback">The method to invoke when information retrieval has completed</param>
        /// <param name="proxyUrl">The URL of a proxy server to use when making the request</param>
        public static void GetServiceInfoAsync(string url, object userState, EventHandler <ServiceEventArgs> callback, string proxyUrl = null)
        {
            string jsonUrl = url.Contains("?") ? url + "&f=json" : url + "?f=json";

            WebUtil.OpenReadAsync(new Uri(jsonUrl), url, (sender, e) =>
            {
                if (e.Error != null)
                {
                    callback(null, new ServiceEventArgs());
                    return;
                }
                string requestUrl = (string)e.UserState;

                MapService mapService = WebUtil.ReadObject <MapService>(e.Result);
                if (mapService != null && mapService.Name != null && mapService.Units != null)
                {
                    mapService.Url           = requestUrl;
                    mapService.RequiresProxy = e.UsedProxy;
                    mapService.InitTitle();
                    callback(null, new ServiceEventArgs()
                    {
                        Service = mapService, UserState = userState
                    });
                    return;
                }

                FeatureService featureService = WebUtil.ReadObject <FeatureService>(e.Result);
                if (featureService != null && featureService.Layers != null && featureService.Layers.Length > 0)
                {
                    featureService.Url           = requestUrl;
                    featureService.RequiresProxy = e.UsedProxy;
                    featureService.InitTitle();
                    callback(null, new ServiceEventArgs()
                    {
                        Service = featureService, UserState = userState
                    });
                    return;
                }

                ImageService imageService = WebUtil.ReadObject <ImageService>(e.Result);
                if (imageService != null && imageService.PixelType != null)
                {
                    imageService.Url           = requestUrl;
                    imageService.RequiresProxy = e.UsedProxy;
                    imageService.InitTitle();
                    callback(null, new ServiceEventArgs()
                    {
                        Service = imageService, UserState = userState
                    });
                    return;
                }

                FeatureLayerService featureLayerService = WebUtil.ReadObject <FeatureLayerService>(e.Result);
                if (featureLayerService != null && featureLayerService.Type == "Feature Layer")
                {
                    featureLayerService.Url           = requestUrl;
                    featureLayerService.RequiresProxy = e.UsedProxy;
                    featureLayerService.Title         = featureLayerService.Name;
                    callback(null, new ServiceEventArgs()
                    {
                        Service = featureLayerService, UserState = userState
                    });
                    return;
                }

                LocatorService locatorService = WebUtil.ReadObject <LocatorService>(e.Result);
                if (locatorService != null && locatorService.CandidateFields != null &&
                    (locatorService.AddressFields != null || locatorService.SingleLineAddressField != null))
                {
                    locatorService.Url           = requestUrl;
                    locatorService.RequiresProxy = e.UsedProxy;
                    locatorService.InitTitle();
                    callback(null, new ServiceEventArgs()
                    {
                        Service = locatorService, UserState = userState
                    });
                    return;
                }

                callback(null, new ServiceEventArgs());
            }, proxyUrl);
        }