Cómo conectar con Mapas de Bing con el SDK de REST para C++

Cómo conectarse a servicios web con el C++ REST SDK (aplicaciones de la Tienda Windows con C++ y XAML)

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows en tiempo de ejecución. Si estás desarrollando para Windows 10, consulta la documentación más reciente

Usa el C++ REST SDK para conectar con Mapas de Bing con C++ en una aplicación de la Tienda Windows. Para los escenarios de C++ en los que quieres escribir código de red HTTP reutilizable que se pueda ejecutar en aplicaciones de escritorio y en ediciones anteriores de Windows o Linux, puedes usar el C++ REST SDK. El C++ REST SDK incluye soporte total de los modelos de programación asincrónica y cuenta con la funcionalidad de análisis de JSON integrada. El SDK se incluye en Microsoft Visual Studio. Para obtener más información, consulta C++ REST SDK.

Para el código que tiene una mayor integración con una aplicación específica con C++ y XAML, se recomienda que uses la clase Windows::Web::Http::HttpClient.

Este tema muestra la manera de conectarse con el extremo REST de la API de ubicación de mapas de Bing y la manera de recuperar datos de ubicación como texto en formato JSON, según las entradas de longitud y latitud. Para más información sobre cómo agregar un mapa de Bing a una aplicación escrita en C++, consulta Crear una aplicación de la Tienda Windows (para Windows 8.1).

Requisitos previos

En los siguientes ejemplos se usa C++ y XAML. Si necesitas ayuda general para crear una aplicación de Windows en tiempo de ejecución con C++, consulta Crear la primera aplicación de Windows en tiempo de ejecución con C++.

Para asegurarte de que la aplicación de la Tienda Windows está lista para la red, debes establecer las funcionalidades de red necesarias en el archivo Package.appxmanifest del proyecto. Para obtener más información, consulta Cómo establecer las funcionalidades de red.

Crear una cuenta con Mapas de Bing y obtener una clave

Dn423314.wedge(es-es,WIN.10).gif

  • Si aún no lo has hecho, primero necesitas obtener una clave que la aplicación usará para acceder al servicio. Sigue las instrucciones en Obtener una clave de Mapas de Bing.

Crear un nuevo proyecto de aplicación vacía de la Tienda Windows con C++

  1. Abre Microsoft Visual Studio 2013 y selecciona Nuevo proyecto en el menú Archivo.
  2. En la lista de plantillas, elige Visual C++.
  3. En la sección, elige Aplicaciones de la Tienda.
  4. En la sección, selecciona Aplicaciones Windows y luego Aplicación vacía.
  5. Asigna el nombre CPPRESTSDKSample a la aplicación y haz clic en Aceptar.

Agregar una referencia al C++ REST SDK

  1. Haz clic en Proyecto | Propiedades y clic en el botón Agregar nueva referencia.
  2. En el cuadro de diálogo Agregar referencia, amplía Windows | Extensiones en la página izquierda y, a continuación, activa la casilla junto a C++ REST SDK en el panel central.
  3. Haz clic en Aceptar para salir del cuadro de diálogo.

Establecer funcionalidades para habilitar el acceso de red

Establece funcionalidades de red en tu aplicación para permitir el acceso a Internet. Para esta aplicación, tendrías que habilitar las funcionalidades de red porque el cliente se va a conectar a servicios web.

Se necesita la funcionalidad Internet (cliente), ya que la aplicación debe poder conectarse como un cliente a un servicio web en Internet.

Nota  En Windows Phone, solo hay una funcionalidad de red, Internet (cliente y servidor), que habilita todo el acceso a redes para la aplicación.
 

Si quieres obtener información más detallada acerca del acceso de red, consulta Cómo configurar las funcionalidades de aislamiento de red.

Estos pasos son necesarios para establecer las funcionalidades de red de una aplicación antes de que se implemente si accede a un servicio web en Internet.

  1. Usa Visual Studio 2013 para abrir el archivo package.appxmanifest.
  2. Selecciona la pestaña Funcionalidad.
  3. Selecciona la funcionalidad Internet (cliente).

  4. Guarda y cierra el archivo de manifiesto.

Crear una clase contenedora para conectar con Mapas de Bing

En este ejemplo crearemos una clase contenedora y la pondremos en un archivo .h y un archivo .cpp aparte que no tengan dependencias en C++/CX o en Windows en tiempo de ejecución para que podamos usarla fácilmente en otros proyectos, incluidos los proyectos de escritorio de Windows. Este código se implementa como una clase con una única función estática, pero podría fácilmente ser una función libre o una clase no estática. También podría empaquetarse en una DLL Win32 o en una biblioteca estática, si esto tuviera más sentido en tu escenario. Para obtener más información, consulta Compilación de aplicaciones y bibliotecas (C++/CX).

  1. En Visual Studio, haz clic en Proyecto | Agregar nuevo elemento y después selecciona Archivo de encabezado y llámalo "BingMapsWrapper.h". Sigue los mismos pasos para crear un nuevo archivo .cpp con el mismo nombre.
  2. Copia el siguiente código en el archivo .h:
    
    #pragma once
    
    #include <string>
    #include <ppltasks.h>
    
    namespace BingMaps
    {
        class BingMapsWrapper
        {
        public:
            concurrency::task<std::wstring> GetLocationAsync(double latitude, double longitude);
        };
    }
    
    
  3. El código para acceder a Mapas de Bing consta de una sola función, GetLocationAsync. Dentro de esa función, la llamada a http_client::request inicia la solicitud HTTP asincrónica y, cuando la respuesta vuelve, pasa a una continuación en la que la aplicación tiene una oportunidad de examinar el código de estado. El cuerpo de la respuesta, una cadena con formato JSON, se pasa a una segunda continuación que lo analiza y concatena los elementos de interés en una cadena que se devuelve al llamante.

    Copia este código en el archivo BingMapsWrapper.cpp:

    
    #include "pch.h"
    #include "BingMapsWrapper.h"
    #include <ppltasks.h>
    #include "http_client.h"
    
    using namespace std;
    using namespace concurrency;
    using namespace BingMaps;
    
    using namespace web;
    using namespace web::json;
    using namespace web::http;
    using namespace web::http::client;
    
    task<wstring> BingMapsWrapper::GetLocationAsync(double latitude, double longitude)
    {
        wstring BingServiceKey = L"INSERT_YOUR_KEY_HERE";
        uri_builder uri(L"http://dev.virtualearth.net/REST/v1/Locations/");
        wostringstream fragment;
        fragment << latitude << L',' << longitude;
        uri.append_path(fragment.str(), true);
        uri.append_query(L"o", L"json");
        uri.append_query(L"key", BingServiceKey.c_str());
    
        http_client client(uri.to_uri());
        return client.request(methods::GET).then([](http_response response) -> task<utility::string_t>
        {
            unsigned long status = response.status_code();
            utility::string_t retval;
    
            // TODO In a real-world app, you should handle connection errors here.
            return response.extract_string();
    
        }).then([this, latitude, longitude](utility::string_t responseBody)
        {
            wstring addressString;
            json::value v;
    
            try
            {
                v = json::value::parse(responseBody);
            }
    
            catch (const json::json_exception&)
            {
                wostringstream ss;
                ss << L"BingLocationService: Failed to parse resource set for (" << latitude << L',' << longitude << ')';
                return addressString.append(ss.str());
            }
    
            const json::value& resourceSets = v[L"resourceSets"];
            int32_t estimatedTotal = resourceSets[0][L"estimatedTotal"].as_integer();
    
            if (estimatedTotal == 0)
            {
                wostringstream ss;
                ss << L"BingLocationService: request for (" << latitude << L',' << longitude << L") returned 0 resources";
                return addressString.append(ss.str());
            }
    
            const json::value& resources = resourceSets[0][L"resources"];
    
            // For more fine-grained control over the parsing, enclose each
            // attempt to read a json value in its own try-catch block.
            try
            {
                auto address = resources[0][L"address"];
                if (address[L"adminDistrict"].is_string())
                {
                    addressString.append(address[L"adminDistrict"].as_string());
                    addressString.append(L", ");
                }
    
                if (address[L"countryRegion"].is_string())
                {
                    addressString.append(address[L"countryRegion"].as_string());
                    addressString.append(L", ");
                }
    
                if (address[L"locality"].is_string())
                {
                    addressString.append(address[L"locality"].as_string());
                }
            }
    
            catch (const json::json_exception& e)
            {
                // A field was not in the payload.
                auto t = e.what();
            }
            return addressString;
        }).then([](task<wstring> result)
        {
            try
            {
                result.get(); // trap exceptions in the task chain           
            }
            catch (const exception& e)
            {
                auto a = e.what();
            }
            return result;
        });
    }
    
    

Crear la interfaz de usuario

Dn423314.wedge(es-es,WIN.10).gif

  1. La interfaz de usuario consiste en dos controles TextBox que sirven para introducir valores de longitud y latitud, un TextBlock que muestra la información de ubicación devuelta por Bing y un botón para iniciar la operación. Agrega el siguiente control StackPanel de XAML a la cuadrícula en MainPage.xaml:

    
     <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Right" Width="1366">
        <TextBlock x:Name="TitleText" HorizontalAlignment="Left" Margin="10,47,0,0" 
            TextWrapping="Wrap" Text="Connect to Bing Maps Web Service with the C++ REST SDK" 
            VerticalAlignment="Top" Height="52" Width="1356" FontSize="36"/>
        <StackPanel HorizontalAlignment="Left" Height="204" Margin="26,117,0,0" VerticalAlignment="Top" Width="922">
            <StackPanel Orientation="Horizontal">
                <TextBlock Padding="0,0,10,0" FontSize="14" Text="Enter a valid longitude:"></TextBlock>
                    <TextBox x:Name="Longitude"  TextWrapping="Wrap" Text="-122.125542" Height="28.519"  
                             UseLayoutRounding="False" Width="149.021" d:LayoutRounding="Auto"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Padding="0,0,10,0" FontSize="14" Text="Enter a valid latitude:" Width="152"></TextBlock>
                    <TextBox x:Name="Latitude" TextWrapping="Wrap" Text="47.642857" Height="28" Width="149"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="0,20,20,20">
                <TextBlock Padding="0,10,10,10" FontSize="14" Text="Bing Maps Response:"></TextBlock>
                    <TextBlock x:Name="BingMapsResponse"  FontSize="14" HorizontalAlignment="Left" TextWrapping="Wrap"  
                    VerticalAlignment="Top" Height="40" Width="744"/>
                </StackPanel>
        <Button x:Name="LocationButton" Content="Get Location" Height="50" Width="150" Click="Button_Click"></Button>
        </StackPanel>
    
        </Grid>
    
    
    
  2. Agrega el controlador del botón para LocationButton. Una forma sencilla de hacer esto es eliminar el controlador existente y escribirlo de nuevo, y permitir que la etiqueta inteligente se encargue de la función en MainPage.xaml.h.

Conectar con la API de ubicación de Mapas de Bing y analizar los resultados

El trabajo real en esta muestra se realiza completamente en el método GetLocationAsync. En este método, primero creamos un URI para enviar al servicio web que incluye los valores de entrada de longitud y latitud, y una cadena de consultas que especifica que queremos la respuesta con formato JSON y que proporciona una clave. Este URI se usa para inicializar un nuevo objeto http_client, que representa una sesión HTTP. Esta clase se define en http_client.h, uno de los encabezados del C++ REST SDK. El método de solicitud empieza como una operación asincrónica que lleva a cabo las acciones definidas en la expresión lambda. En este caso, se solicita una operación GET. Cuando la operación finaliza, la respuesta del servidor se devuelve y se pasa al método .then, que se denomina una continuación. En esta continuación, analizamos el texto JSON y escribimos los resultados en el TextBlock apropiado de nuestra interfaz de usuario. Usamos el objeto task_options para especificar que necesitamos ejecutar la continuación en el subproceso UI. Esto es necesario porque estamos escribiendo directamente en el control TextBlock de XAML.

  1. Copia este código en MainPage.xaml.h:
    
    //
    // MainPage.xaml.h
    // Declaration of the MainPage class.
    //
    
    #pragma once
    
    #include "MainPage.g.h"
    
    
    namespace CPPRESTSDKSample
    {
    	  /// <summary>
    	  /// An empty page that can be used on its own or navigated to within a Frame.
      	/// </summary>
    	  public ref class MainPage sealed
    	  {
    	  public:
    		    MainPage();
    	  private:
    		    void GetLocation(float latitude, float longitude);		
    		    void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    	};
    }
    
    
    
  2. El código de la interfaz de usuario es bastante simple. Solo hay que llamar a concurrency::create_task para crear una IAsyncOperation y convertir el resultado de std::wstring en Platform:String, que después insertamos en el bloque de texto adecuado.

    Reemplaza todo el contenido de MainPage.xaml.cpp con este código:

    
    //
    // MainPage.xaml.cpp
    // Implementation of the MainPage class.
    //
    
    #include "pch.h"
    #include "MainPage.xaml.h"
    #include "http_client.h"
    #include <memory>
    #include <assert.h>
    #include <sstream>
    #include "BingMapsWrapper.h"
    
    using namespace CPPRESTSDKSample;
    using namespace concurrency;
    using namespace web;
    using namespace web::json;
    using namespace web::http;
    using namespace web::http::client;
    
    using namespace std;
    using namespace BingMaps;
    
    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Controls::Primitives;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Input;
    using namespace Windows::UI::Xaml::Media;
    using namespace Windows::UI::Xaml::Navigation;
    
    // The Blank Page item template is documented at http://go.microsoft.com/fwlink/p/?LinkID=234238
    
    MainPage::MainPage()
    {
        InitializeComponent();
    }
    
    
    void MainPage::GetLocation(float latitude, float longitude)
    {
        BingMapsWrapper wrapper;
        task_options options;
        options.set_continuation_context(task_continuation_context::use_current());
    
        create_task(wrapper.GetLocationAsync(latitude, longitude)).then
            ([this](wstring result)
        {
            BingMapsResponse->Text = ref new String(result.c_str());
        }, options);
    }
    
    
    void CPPRESTSDKSample::MainPage::Button_Click(Object^ sender, RoutedEventArgs^ e)
    {
        wstringstream converter;
        float longitude = 0;
        float latitude = 0;
    
        converter.precision(12);
        converter.fill('0');
        converter.setf(std::ios::fixed, std::ios::floatfield);
    
        converter << this->Longitude->Text->Data();
        converter >> longitude;
    
        converter.clear();
        converter << this->Latitude->Text->Data();
        converter >> latitude;
    
        GetLocation(latitude, longitude);
    }
    
    
    

La respuesta JSON sin procesar

El siguiente fragmento de código muestra la respuesta completa que vuelve del servicio web de Mapas de Bing como respuesta a nuestra solicitud HTTP.

{
   "authenticationResultCode": "ValidCredentials",
   "brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
   "copyright": "Copyright © 2013 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
   "resourceSets": [
      {
         "estimatedTotal": 1,
         "resources": [
            {
               "__type": "Location:http://schemas.microsoft.com/search/local/ws/rest/v1",
               "bbox": [
                  47.636272,
                  -122.13744,
                  47.643997,
                  -122.12216
               ],
               "name": "Microsoft Way, Redmond, WA 98052",
               "point": {
                  "type": "Point",
                  "coordinates": [
                     47.640137,
                     -122.12981
                  ]
               },
               "address": {
                  "addressLine": "Microsoft Way",
                  "adminDistrict": "WA",
                  "adminDistrict2": "King Co.",
                  "countryRegion": "United States",
                  "formattedAddress": "Microsoft Way, Redmond, WA 98052",
                  "locality": "Redmond",
                  "postalCode": "98052"
               },
               "confidence": "Medium",
               "entityType": "Address",
               "geocodePoints": [
                  {
                     "type": "Point",
                     "coordinates": [
                        47.640137,
                        -122.12981
                     ],
                     "calculationMethod": "Interpolation",
                     "usageTypes": [
                        "Display",
                        "Route"
                     ]
                  }
               ],
               "matchCodes": [
                  "Good"
               ]
            }
         ]
      }
   ],
   "statusCode": 200,
   "statusDescription": "OK",
   "traceId": "0a734b03d01b483b9e3b80216e831cac|BAYM000274|02.00.161.1800|BY2MSNVM000002, BY2MSNVM001076"
}


Temas relacionados

Otros recursos
Conexión a servicios web
Controlar excepciones en aplicaciones de red
Cómo configurar las funcionalidades de red
Cómo habilitar el bucle invertido y depurar el aislamiento de red
Referencia
C++ REST SDK

 

 

Mostrar:
© 2017 Microsoft