To Use OpenStreetMap and draw marker we can use a javascript library, there’s a lot out there but for this example well use leafletjs.com. It’s open source, mobile friendly and lightweight and has a complete features most developers need.
Leafletjs
Now head over to the website and follow the quick start tutorial, that should be enough to get started. After you follow the tutorial, you can create a simple web application with ASP.NET Core with MVC template (follow this tutorial). Add a new controller, name it MapController then create Index.cshtml view for it. Inside the View, include the leafletjs css style and its script inside the head section of the page to initialize the map and don’t forget to put a div element with a certain id inside the body element. This div element is where you want your map would be.
The web application would have a feature like this: everytime a user enter a text inside the search box and click on a search button, we will search the database for the airport’s name. By calling on the MapController Search action via HttpGet Ajax Request. Once the result came out with the result of Airport[], the app will add marker(s) and put the result on the map. So the user can see the airports data on the map by putting a marker at its location.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@{ | |
ViewData["Title"] = "Map"; | |
} | |
<h2>@ViewData["Title"]</h2> | |
@section HeadScripts{ | |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css" | |
integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" | |
crossorigin=""/> | |
<script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js" | |
integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q==" | |
crossorigin=""></script> | |
<style type="text/css"> | |
#peta{ | |
height: 500px; | |
width: auto; | |
margin: 0 auto; | |
border: 0.2em solid #c75c41; | |
box-shadow: #55322a; | |
} | |
</style> | |
} | |
<div class="form-group col-md-4"> | |
<label>Airport Name:</label> | |
<input type="text" id="airportName" class="form-control" /> | |
<input type="button" id="btnsubmit" value="Search" class="btn btn-default"/> | |
</div> | |
<div id="peta"></div> | |
@section Scripts{ | |
<script type="text/javascript"> | |
$(document).ready(function(){ | |
var mymap = L.map('peta').locate({setView:true, maxZoom:5}); | |
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', { | |
maxZoom: 18, | |
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' + | |
'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' + | |
'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>', | |
id: 'mapbox.streets' | |
}).addTo(mymap); | |
var markers = []; | |
var polyLines = []; | |
function Mapping(data){ | |
for(let idx=0; idx < markers.length; idx++){ | |
markers[idx].removeFrom(mymap); | |
} | |
markers = []; | |
for (let index = 0; index < data.length; index++) { | |
const element = data[index]; | |
console.log(element); | |
var marker = L.marker([element.latitude, element.longitude], { title: element.name +" – " +element.code}).addTo(mymap); | |
marker.bindPopup(element.name +"("+element.code+")").openPopup(); | |
markers.push(marker); | |
polyLines.push([element.latitude, element.longitude]); | |
if(index===0){ | |
mymap.center = [element.latitude, element.longitude]; | |
} | |
} | |
} | |
$('#btnsubmit').click(function(e){ | |
var airportname= $('#airportName').val(); | |
$.ajax({ | |
url:'/map/search?name='+airportname, | |
method:'GET', | |
success: function(d){ | |
console.log(d); | |
Mapping(d); | |
}, | |
error: function(msg){ | |
console.log(msg); | |
} | |
}); | |
}); | |
}); | |
</script> | |
} |
Airport Data
Since this application will fetch a Geolocation data in a form of Latitude and Longitude, for that we’ll create a table with Columns: Airport Name, Latitude, Longitude, Country and City. Create the Table called AIRPORTS and insert the data from openflights.org (download). The additional information like Country and City is for clarity only, we dont want to only show the airports name and its location because it would be confusing for the user. A country and a city where the airport is located will add more information for the user. We’ll build simple map, with a textbox for searching an airport by its name.
This sql command is for creating the Table :
Create table AIRPORTS(ID INT PRIMARY KEY IDENTITY(1,1), Name varchar(350) not null,Code varchar(10), Latitude varchar(50) not null, Longitude varchar(50) not null,City varchar(50) not null, Country varchar(50) not null);

Dapper
To access the data from database, we’ll use a simple object mapper for .NET called Dapper. Using this library we don’t need to manage the SqlConnection, we can execute a query and map the results into a strongly typed list. Or execute a command (insert, update, delete), a stored procedure with a sweeping fast query time. This is one of my favorite nuget package, and I use it regularly on many different projects.
ASP.Net Core
The web application itself has no authentication, let it open so anyone can access it. To make things easier on the data access, create a Repository class and called it AirportRepository. Using Dapper we only need to declare a private member for the SqlConnection and a constant string for the ConnectionString. The repository only have one method for searching the airport data by its name.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Data.SqlClient; | |
using Dapper; | |
namespace tracking.Models | |
{ | |
public class AirportRepository{ | |
// change the user id and password accordingly. | |
private const string connstring = "Data Source=.\\sqlexpress;Initial Catalog=OSM_DB;user id=[id]; password=[password]"; | |
private SqlConnection Connection; | |
public AirportRepository() | |
{ | |
this.Connection = new SqlConnection(connstring); | |
} | |
public IEnumerable<Airport> Search(string name){ | |
name = "%"+name+"%"; | |
var data = Connection.Query<Airport>(@"select top 100 Name,Code,Latitude,Longitude,City,Country from airports | |
where name like @name", new {name}); | |
if(data!=null) | |
{ | |
return data; | |
} | |
return null; | |
} | |
} | |
} |
Don’t forget to add a private member of AirportRepository inside MapController and add a Constructor with one parameter which took a Repository instance. This is dependency injection via Constructor, it’s a common pattern that developers often uses its also a built in feature that comes with asp.net core by design. In order for the Constructor to get an instance of the Repository, we have to register the Repository as dependency on Startup.cs, you can read more about dependency injection in asp.net core here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.AspNetCore.HttpsPolicy; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using tracking.Models; | |
namespace tracking | |
{ | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.Configure<CookiePolicyOptions>(options => | |
{ | |
// This lambda determines whether user consent for non-essential cookies is needed for a given request. | |
options.CheckConsentNeeded = context => true; | |
options.MinimumSameSitePolicy = SameSiteMode.None; | |
}); | |
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); | |
services.AddScoped<GPSLocRepository>(); | |
services.AddScoped<AirportRepository>(); | |
} | |
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
else | |
{ | |
app.UseExceptionHandler("/Home/Error"); | |
app.UseHsts(); | |
} | |
//app.UseHttpsRedirection(); | |
app.UseStaticFiles(); | |
app.UseCookiePolicy(); | |
app.UseMvc(routes => | |
{ | |
routes.MapRoute( | |
name: "default", | |
template: "{controller=Home}/{action=Index}/{id?}"); | |
}); | |
} | |
} | |
} |
That’s it, a short introduction for using Openstreetmap and leafletjs in you web application as an alternative of googlemaps. You can download the source code here.