Azure Maps Service – real time location in UWP application

Short introduction

New great service appeared with status “General Availability” in Azure portal – Azure Maps . It is a collection of geo-spatial services, backed by fresh mapping data. It contains REST APIs for rendering maps, searching points of interest, routes to points of interests, traffic conditions, time zones, and IP to location services. In this article I would like to present how to use Azure Maps service together with Azure Signal R service to display real time position together with route drawn on the map. I already explained what Azure Signal R service is in my previous article here.

In this article I want to show how to display real time location together with route in the UWP application. Please read above article first before moving forward.

Solution structure

To simulate real-time transport data I prepared three applications for this solution:

  • ASP .NET Core Web API – web API integrated with Azure SignalR service and Azure Maps service to send real-time transport data to client app and return whole route which should be drawn on the map
  • Console App – created to send fake location data to Web API about transport
  • Universal Windows App – client application to display information on the map about driver and the route

Setup Azure Maps Service

Open Microsoft Azure portal. Type “Azure Maps” in search window:

Fill required information like name of the service (used later with full URL):

Once service is created open the tab and select “Keys” section:

Copy Primary Key because we will use it later in Web API application setup.

Setup ASP .NET Core Web API

We will use ASP .NET Core Web API application created in the previous article available here. Connection with Signal R Service is already configured but we have to add functionality connected with generating route basing on the coordinates. Here Azure Maps enters the game.

We will comunicate with Azure Maps REST API using RestSharp. Clone project from my Github here , open it. You should see that RestSharp NuGet package is added:

Now open “MapService” class from “Services” folder:

public interface IMapService
    {
        Task<DirectionsResponse> GetDirections(DirectionsRequest directionsRequest);
    }

    public class MapService : IMapService
    {
        private AzureMapsSettings _azureMapsSettings;
        private RestClient _restClient;

        public MapService(IOptions<AzureMapsSettings> azureMapSettings)
        {
            _azureMapsSettings = azureMapSettings.Value;
            _restClient = new RestClient("https://atlas.microsoft.com");
        }

        public async Task<DirectionsResponse> GetDirections(DirectionsRequest directionsRequest)
        {
            var request = new RestRequest("route/directions/json", Method.GET);
            request.AddQueryParameter("subscription-key", _azureMapsSettings.SubscriptionKey);
            request.AddQueryParameter("api-version", "1.0");
            request.AddQueryParameter("query", $"{directionsRequest.FromLatitude},{directionsRequest.FromLongitude}:{directionsRequest.ToLatitude},{directionsRequest.ToLongitude}");
            var response = await _restClient.ExecuteTaskAsync<string>(request, default(CancellationToken));
            var directions = JsonConvert.DeserializeObject<DirectionsResponse>(response.Data);
            return directions;
        }
    }

As you can see we have to pass from and to coordinates (latitude and longitude). We have to also provide map key copied from Azure portal – it is passed in “subscription-key” header. In this case we are using directions endpoint to retrieve route between two points on the map.

In the “Model” folder you can find two classed related with Azure Maps API request: “DirectionsRequest” – instance of this class is passed to “GetDirections” method.  There is also “DirectionsResponse” – this class represents data returned form the Azure Maps.

When you open MapsController class you should see Post method with “DirectionsRequst” parameter:

 public class MapController : Controller
    {
        private IMapService _mapService;

        public MapController(IMapService mapService)
        {
            _mapService = mapService;
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] DirectionsRequest directionsRequest)
        {
            var directions = await _mapService.GetDirections(directionsRequest);
            if (directions == null)
                return NotFound();
            return Ok(directions);
        }
    }

Setup .NET Core Console App

I modified the code of test console application. We are using it to simulate position change of the driver – then we are displaying new position on the map in the UWP application. You can find updated code here.

    class Program
    {
        static void Main(string[] args)
        {
            List<LocationUpdate> locationUpdates = new List<LocationUpdate>
            {
             new LocationUpdate
                {
                    Latitude = 52.23292,
                    Longitude = 20.99114,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 52.25229,
                    Longitude = 20.94341,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 52.19462,
                    Longitude = 20.82109,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 52.09011,
                    Longitude = 20.36584,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 52.01813,
                    Longitude = 19.97684,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 51.87744,
                    Longitude = 19.64773,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 51.13844,
                    Longitude = 16.93472,
                    DriverName = "Daniel"
                },
             new LocationUpdate
                {
                    Latitude = 51.12705,
                    Longitude = 16.92196,
                    DriverName = "Daniel"
                },
            };

            var hubClient = new ClientSignalR();
            hubClient.Initialize("http://localhost:63369/transport");

            Observable
            .Interval(TimeSpan.FromSeconds(3))
            .Subscribe(
                async x =>
                {
                    var locationUpdate = locationUpdates.FirstOrDefault();
                    if(locationUpdate !=null)
                    {
                        await hubClient.SendHubMessage("broadcastMessage", locationUpdate);
                        Console.WriteLine("SENDING LOCATION UPDATE: " + locationUpdate.DriverName + " " + locationUpdate.Latitude + " " + locationUpdate.Longitude);
                        locationUpdates.Remove(locationUpdate);
                    }
                    else
                    Console.WriteLine("UPDATES COMPLETED");
                });

            Console.ReadKey();
        }
    }

Setup Universal Windows Platform app

I used previously created UWP application and added functionality related with displaying route on the map. Now application displays route using Azure Maps and live location updates using Signal R Service. You can see updated source code here.

Open “Services” folder and “MapService” class. As you can see I am using RestSharp to make request to previously created Web API and retrieve directions data to display route on the map.

 public class MapService
    {
        private RestClient _restClient;

        public MapService()
        {
            _restClient = new RestClient("http://localhost:63369/api");
        }

        public async Task<DirectionsResponse> GetDirections(DirectionsRequest directionsRequest)
        {
            var request = new RestRequest("map", Method.POST);
            request.AddParameter("application/json; charset=utf-8", JsonConvert.SerializeObject(directionsRequest), ParameterType.RequestBody);
            var response = await _restClient.ExecuteTaskAsync<string>(request, default(CancellationToken));
            var directions = JsonConvert.DeserializeObject<DirectionsResponse>(response.Data);
            return directions;
        }
    }

Now open “MapManager” class – here I added “DisplayRoute” method. As a parameter there is response from Azure Maps – “DirectionsResponse”. New MapPolyline object is created. Please note that path property is instantiated with response from Azure Maps to display the route. Then new list with map elements is created and at the end we are adding new layer to the map with the route:

public void DisplayRoute(DirectionsResponse directions)
        {
            MapPolyline routeLine = new MapPolyline()
            {
                Path = new Geopath(directions.routes[0].legs[0].points.Select(p => new BasicGeoposition { Latitude = p.latitude, Longitude = p.longitude })),
                StrokeColor = Colors.Black,
                StrokeThickness = 3,
                StrokeDashed = true
            };


            var mapLines = new List<MapElement>();

            mapLines.Add(routeLine);

            var LinesLayer = new MapElementsLayer
            {
                ZIndex = 1,
                MapElements = mapLines
            };

            _map.Layers.Add(LinesLayer);
        }

Test solution

You can test solution locally or publish ASP .NET Core Web API on Azure as Web App. To test on localhost launch applications in such order:

  • Web API –
  • UWP application
  • Console application

Final result should look like below:

Wrapping up

In this article I presented how to configure Azure Maps service together with Azure SignalR Service and pass real-time location data to UWP application including display of the current route. You can test this PoC yourself. You can find source code on my GitHub – Web API appconsole test appUWP application.

Advertisements