Using the TomTom Maps SDK for Web with ASP.NET Core, Part 2

In our last article, we've shown how to quickly create and run a mapping-enabled website with ASP.NET Core MVC as a server component and TomTom Maps SDK for Web as our client JavaScript mapping library. The solution featured markers that helped users quickly visualize the location of landmarks on the map.
This time, we'll improve the existing website by building new features on top of the existing codebase. We'll learn how to draw polygons to highlight landmark boundaries, which separate famous places from their surroundings. Also, we'll add hyperlinks to the markers to zoom in to the selected locations.
To follow the separation of concerns principle, we'll modify our solution's architecture by creating a new ASP.NET Core Web API and make it store and serve mapping-related data to the MVC project.
Adding Areas
Let’s improve our web app to provide a rectangle to represent the perimeter of the landmark. The first step is to provide additional coordinates to our JSON file:
1{23 "Places": [45 {67 "id": 1,89 "name": "Central Park, N.Y., United States",1011 "zoom": 12,1213 "center": [ -73.9712, 40.7831 ],1415 "coordinates": [1617 [1819 [ -73.9582, 40.8007 ],2021 [ -73.9491, 40.7968 ],2223 [ -73.9730, 40.7642 ],2425 [ -73.9819, 40.7681 ],2627 [ -73.9582, 40.8007 ]2829 ]3031 ]3233 },3435 {3637 "id": 2,3839 "name": "Plaza Mayor, Madrid, Spain",4041 "zoom": 17,4243 "center": [ -3.7074, 40.4155 ],4445 "coordinates": [4647 [4849 [ -3.70670, 40.41584 ],5051 [ -3.70815, 40.41579 ],5253 [ -3.70805, 40.41493 ],5455 [ -3.70664, 40.41500 ],5657 [ -3.70670, 40.41584 ]5859 ]6061 ]6263 },6465 {6667 "id": 3,6869 "name": "Taj Mahal Garden, Agra, India",7071 "zoom": 13,7273 "center": [ 78.0421, 27.1732 ],7475 "coordinates": [7677 [7879 [ 78.04379, 27.17450 ],8081 [ 78.04040, 27.17450 ],8283 [ 78.04040, 27.17172 ],8485 [ 78.04379, 27.17172 ],8687 [ 78.04379, 27.17450 ]8889 ]9091 ]9293 },9495 {9697 "id": 4,9899 "name": "Red Square, Moscow, Russia",100101 "zoom": 15,102103 "center": [ 37.61970, 55.75432 ],104105 "coordinates": [106107 [108109 [ 37.61897, 55.75521 ],110111 [ 37.61825, 55.75478 ],112113 [ 37.62172, 55.75322 ],114115 [ 37.62222, 55.75363 ],116117 [ 37.61897, 55.75521 ]118119 ]120121 ]122123 }124125 ]126127}
Now we have two new properties: zoom, to adjust the map view, and coordinates, to provide the perimeter points. We’ll create those properties in the Place class as well:
1public class Place23{45 ...67 public long zoom { get; set; }89 public double[][][] coordinates { get; set; }1011}
Let’s then modify the showPlace() function to use the new zoom property:
1function showPlace(id) {23 $.ajax('http://localhost:5000/Home/GetPlace/' + id)45 .done(function (place) {67 $('#placeName').html(place.name);89 map.jumpTo({1011 zoom: place.zoom,1213 center: place.center1415 });1617 });1819}
With TomTom Maps SDK for Web, we can add a new layer where a polygon can be rendered to highlight the place of interest:
1function initialize() {23 map = tt.map({45 key: myTomTomKey,67 container: 'map',89 style: 'tomtom://vector/1/basic-main'1011 });1213 map.on('load', function () {1415 for (var i = 0; i < famousPlaces.length; i++) {1617 let place = famousPlaces[i];1819 var marker = new tt.Marker().setLngLat(place.center).addTo(map);2021 var popupOffsets = {2223 bottom: [0, -40]2425 }2627 var popup = new tt.Popup({ offset: popupOffsets }).setHTML(place.name);2829 marker.setPopup(popup);3031 map.addLayer({3233 'id': 'overlay' + place.id,3435 'type': 'fill',3637 'source': {3839 'type': 'geojson',4041 'data': {4243 'type': 'Feature',4445 'geometry': {4647 'type': 'Polygon',4849 'coordinates': place.coordinates5051 }5253 }5455 },5657 'layout': {},5859 'paint': {6061 'fill-color': '#db356c',6263 'fill-opacity': 0.5,6465 'fill-outline-color': 'black'6667 }6869 });7071 }7273 });7475}
When we run the app, we can see the borders of our landmarks:
Let’s make our markers show a link for navigating to the particular map of each landmark:
var popup = new tt.Popup({ offset: popupOffsets }).setHTML('<a href="javascript: showPlace(' + place.id + ');">' + place.name + '</a>');
And voilà! Now we can easily navigate to the Taj Mahal map:
Serving Data with the ASP.NET Core Web API
So far, we’ve been able to develop our web application using only the ASP.NET Core MVC Project. Working with a single ASP.NET Core project is quite simple. However, real-world scenarios might demand a more complex architecture.
Best practices and guidelines advise developers to split a solution into different projects, each with a distinct set of responsibilities. For example, an MVC project will deal with web application execution, but will not involve data storage or manipulation. Thus, we need a new project to fulfill those roles.
Let’s fill this gap by creating a new ASP.NET Core Web API project, and moving the data management from the MVC project to the Web API project.
First, create a new project as in the first part of this tutorial. Then right-click the project name, choose the Debug tab, and assign port 5001 to the Web API project URL:
Now we have a solution with two projects, which must run at the same time. Right-click the solution name, choose the Set Startup Projects menu, then choose Multiple startup projects:
Create a new \Models folder for the project, then copy and paste the Places.cs file we’re using in the MVC project into that folder:
Next, create a new \Data folder and copy the famous-places.json file to that folder:
Now add a new controller, named PlacesController, to the Web API project. Include in it the following code, which is similar to what we created for the MVC project.
1[ApiController]23[Route("[controller]")]45public class PlacesController : ControllerBase67{89 private readonly ILogger<PlacesController> _logger;1011 public PlacesController(ILogger<PlacesController> logger)1213 {1415 _logger = logger;1617 }1819 [HttpGet]2021 public async Task<PlaceCollection> Get()2223 {2425 return await GetPlaceCollection();2627 }2829 [HttpGet("{id}")]3031 public async Task<Place> Get(int id)3233 {3435 var collection = await GetPlaceCollection();3637 return collection.Places.Where(p => p.id == id).Single();3839 }4041 private async Task<PlaceCollection> GetPlaceCollection()4243 {4445 var file = Path.Combine(Directory.GetCurrentDirectory(),4647 "Data", "famous-places.json");4849 string json = await System.IO.File.ReadAllTextAsync(file);5051 return PlaceCollection.FromJson(json);5253 }5455}
When the Web API app runs, you can test two endpoints. The first one gives you the full landmark collection:
The second endpoint returns detailed data on a specific location:
Now let’s go back to the MVC project and refactor both the IndexAsync() and GetPlace() actions. Here, we implement calls to the Web API endpoints through the HttpClient class, and return the results as deserialized objects:
1public async Task<IActionResult> IndexAsync()23{45 ViewData["MyTomTomKey"] = MyTomTomKey;67 using (var client = new HttpClient())89 {1011 var response = await client.GetAsync("http://localhost:5001/places");1213 var json = await response.Content.ReadAsStringAsync();1415 var placeCollection = PlaceCollection.FromJson(json);1617 return View("Index", placeCollection);1819 }2021}2223public async Task<JsonResult> GetPlace(int id)2425{2627 using (var client = new HttpClient())2829 {3031 var response = await client.GetAsync($"http://localhost:5001/places/{id}");3233 var json = await response.Content.ReadAsStringAsync();3435 var place = Place.FromJson(json);3637 return new JsonResult(place);3839 }4041}
After these changes, the responsibility for providing data will belong to the Web API project. If you want to secure the Web API connections, read the relevant Microsoft documentation.
Conclusion
As you can see, TomTom Maps SDK is easy to use for developers and software engineers working with the powerful ASP.NET Core.
Although TomTom Maps SDK for Web is a JavaScript library, data can be easily pushed to the client-side code using the ASP.NET Core’s Razor engine to dynamically render UI content. In addition to ASP.NET Core, developers can use TomTom Map SDK for Web with other server-side stacks, like Node.JS, Java/Spring, Python/Django, and Ruby on Rails. JavaScript code can also retrieve mapping data residing on the server side using AJAX requests.
Since ASP.NET Core is a server-side framework, it provides the ideal place to securely deliver data using RESTful web API data services to the client-side code.