示例#1
0
        /// <summary>
        /// Deserializes a GeocodeFeed from an XML stream.
        /// </summary>
        /// <param name="stream">GeocodeFeed XML feed stream.</param>
        /// <returns>A GeocodeFeed that has been parsed from a stream.</returns>
        public static Task <GeocodeFeed> ReadAsync(Stream stream)
        {
            return(Task.Run <GeocodeFeed>(() =>
            {
                GeocodeFeed feed = null;

                var ms = new MemoryStream();

                try
                {
                    stream.CopyTo(ms);
                    if (BingMapsSDSToolkit.Internal.XmlUtilities.IsStreamCompressed(ms))
                    {
                        //Uncompress the first file in the zipped stream.
                        var zipArchive = new System.IO.Compression.ZipArchive(ms);
                        if (zipArchive.Entries != null && zipArchive.Entries.Count > 0)
                        {
                            stream = zipArchive.Entries[0].Open();

                            ms = new MemoryStream();
                            stream.CopyTo(ms);
                        }
                    }

                    ms.Position = 0;

                    var serializer = new XmlSerializer(typeof(GeocodeFeed), "http://schemas.microsoft.com/search/local/2010/5/geocode");
                    feed = (GeocodeFeed)serializer.Deserialize(ms);
                }
                catch { }

                ms.Dispose();
                return feed;
            }));
        }
示例#2
0
        private static GeocodeFeed ParseDelimitedFile(StreamReader textReader, BatchFileFormat format)
        {
            char delimiter;

            switch (format)
            {
            case BatchFileFormat.PIPE:
                delimiter = '|';
                break;

            case BatchFileFormat.TAB:
                delimiter = '\t';
                break;

            case BatchFileFormat.CSV:
            default:
                delimiter = ',';
                break;
            }

            var    feed          = new GeocodeFeed();
            double schemaVersion = 1.0;

            using (var reader = new DelimitedFileReader(textReader, delimiter))
            {
                var row = reader.GetNextRow();

                if (row != null && row.Count > 0)
                {
                    //Parse Schema Version info.
                    if (row[0].StartsWith("Bing Spatial Data Services", StringComparison.OrdinalIgnoreCase) && row.Count >= 2)
                    {
                        double.TryParse(row[1], out schemaVersion);
                        row = reader.GetNextRow();
                    }

                    //Skip header
                    if (string.Compare(row[0], "Id", StringComparison.OrdinalIgnoreCase) == 0 ||
                        string.Compare(row[0], "GeocodeEntity/@Id", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        row = reader.GetNextRow();
                    }

                    //Parse rows
                    while (row != null && row.Count > 0)
                    {
                        var parsedRow = ParseRow(row, schemaVersion);

                        if (parsedRow != null)
                        {
                            feed.Entities.Add(parsedRow);
                        }

                        row = reader.GetNextRow();
                    }
                }
            }

            return(feed);
        }
        /// <summary>
        /// Creates a geocode dataflow job and uploads spatial data to process.
        /// </summary>
        /// <param name="dataFeed">The address data to geocode.</param>
        /// <param name="bingMapsKey">The Bing Maps Key to use for this job. The same key is used to get job status and download results.</param>
        /// <returns>A URL that defines the location of the geocode dataflow job that was created.</returns>
        private async Task <string> CreateJob(GeocodeFeed dataFeed, string bingMapsKey)
        {
            var tcs = new TaskCompletionSource <string>();

            //Build the HTTP URI that will upload and create the geocode dataflow job
            Uri createJobUri = new Uri("https://spatial.virtualearth.net/REST/v1/dataflows/geocode?input=xml&clientApi=SDSToolkit&key=" + bingMapsKey);

            //Include the data to geocode in the HTTP request
            var request = HttpWebRequest.Create(createJobUri);

            // The HTTP method must be 'POST'.
            request.Method = "POST";
            //request.ContentType = "application/xml";
            request.ContentType = "application/octet-stream";

            using (var requestStream = await request.GetRequestStreamAsync())
            {
                using (var zipStream = new GZipStream(requestStream, CompressionMode.Compress))
                {
                    await dataFeed.WriteAsync(zipStream);
                }
            }

            request.BeginGetResponse((a) =>
            {
                var r = (HttpWebRequest)a.AsyncState;

                try{
                    using (var response = (HttpWebResponse)r.EndGetResponse(a))
                    {
                        // If the job was created successfully, the status code should be
                        // 201 (Created) and the 'Location' header should contain a URL
                        // that defines the location of the new dataflow job. You use this
                        // URL with the Bing Maps Key to query the status of your job.
                        if (response.StatusCode != HttpStatusCode.Created)
                        {
                            tcs.SetException(new Exception("An HTTP error status code was encountered when creating the geocode job."));
                        }

                        string dataflowJobLocation = response.Headers["Location"];
                        if (String.IsNullOrEmpty(dataflowJobLocation))
                        {
                            tcs.SetException(new Exception("The 'Location' header is missing from the HTTP response when creating a goecode job."));
                        }

                        tcs.SetResult(dataflowJobLocation);
                    }
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
            }, request);

            return(await tcs.Task);
        }
        /// <summary>
        /// Downloads job results to files names Success.txt (successfully geocoded results) and Failed.txt (info about spatial data that was not geocoded successfully).
        /// </summary>
        /// <param name="statusDetails">Inclues job status and the URLs to use to download all geocoded results.</param>
        /// <param name="bingMapsKey">The Bing Maps Key for this job. The same key is used to create the job and get job status. </param>
        private async Task <BatchGeocoderResults> DownloadResults(DownloadDetails statusDetails, string bingMapsKey)
        {
            var results = new BatchGeocoderResults();

            //Write the results for data that was geocoded successfully to a file named Success.xml
            if (statusDetails.SucceededUrl != null && !statusDetails.SucceededUrl.Equals(String.Empty))
            {
                //Create a request to download successfully geocoded data. You must add the Bing Maps Key to the
                //download location URL provided in the response to the job status request.
                var successUriBuilder = new UriBuilder(statusDetails.SucceededUrl + "?clientApi=SDSToolkit&key=" + bingMapsKey);

                var successfulRequest = (HttpWebRequest)WebRequest.Create(successUriBuilder.Uri);
                successfulRequest.Method = "GET";

                using (var response = (HttpWebResponse)await successfulRequest.GetResponseAsync())
                {
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new Exception("An HTTP error status code was encountered when downloading results.");
                    }

                    using (var receiveStream = response.GetResponseStream())
                    {
                        results.Succeeded = await GeocodeFeed.ReadAsync(receiveStream);
                    }
                }
            }

            //If some spatial data could not be geocoded, write the error information to a file called Failed.xml
            if (statusDetails.FailedUrl != null && !statusDetails.FailedUrl.Equals(String.Empty))
            {
                var failedRequest = (HttpWebRequest)WebRequest.Create(new Uri(statusDetails.FailedUrl + "?clientApi=SDSToolkit&key=" + bingMapsKey));
                failedRequest.Method = "GET";

                using (var response = (HttpWebResponse)await failedRequest.GetResponseAsync())
                {
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new Exception("An HTTP error status code was encountered when downloading results.");
                    }

                    using (Stream receiveStream = response.GetResponseStream())
                    {
                        results.Failed = await GeocodeFeed.ReadAsync(receiveStream);
                    }
                }
            }

            return(results);
        }
        /// <summary>
        /// Method to geocode a set of data.
        /// </summary>
        /// <param name="dataFeed">GeocodeFeed which contains the data to batch geocode/reverse geocode.</param>
        /// <param name="bingMapsKey">Bing Maps key to use for accessing service.</param>
        /// <returns>The results of the batch geocoding process.</returns>
        public async Task <BatchGeocoderResults> Geocode(GeocodeFeed dataFeed, string bingMapsKey)
        {
            BatchGeocoderResults results;

            try
            {
                ReportStatus("Creating batch geocode job.");

                string dataflowJobLocation = await CreateJob(dataFeed, bingMapsKey);

                ReportStatus("Job created and being processed.");

                //Continue to check the dataflow job status until the job has completed
                var statusDetails = new DownloadDetails();

                do
                {
                    statusDetails = await CheckStatus(dataflowJobLocation, bingMapsKey);

                    if (statusDetails.JobStatus == "Aborted")
                    {
                        ReportStatus("Batch geocode job aborted.");
                        return(new BatchGeocoderResults()
                        {
                            Error = "Batch geocode job was aborted due to an error."
                        });
                    }

                    if (statusDetails.JobStatus.Equals("Pending"))
                    {
                        await Task.Delay(_statusUpdateInterval);
                    }
                }while (statusDetails.JobStatus.Equals("Pending"));

                ReportStatus("Batch geocode job completed. Downloading results.");
                results = await DownloadResults(statusDetails, bingMapsKey);

                ReportStatus("Batch geocode results downloaded.");
            }
            catch (Exception ex)
            {
                results = new BatchGeocoderResults()
                {
                    Error = ex.Message
                };
            }

            return(results);
        }