Adding Restaurants to a Map
Reading
Adding Restaurants to a Map
Another nice feature would be to show the list of restaurants on a map. To map
these restaurants, we need to know precisely where the restaurants are. The
process of turning an address into a position, as well as turning a position
into an address, is known as
Geocoding
When geocoding an address, we are often turning the address's text, its street
number, and name, along with the city, state, and zip/postal code, into a pair
of numbers. These decimal numbers,
latitude
and longitude
describe a single position on the surface of the planet.
Adding columns to store a coordinate
Let's get ready for our geocoding practice by adding columns to our
Restaurants
table to store these values.
public double Latitude { get; set; }public double Longitude { get; set; }
Then we will generate a migration for these columns and update the database
dotnet ef migrations add AddLatitudeAndLongitudeToRestaurant
dotnet ef database update
Adding a package to help us geocode
To turn the restaurant's address into a latitude and longitude, we will use a third-party library.
dotnet add package Geocoding.Core
dotnet add package Geocoding.Microsoft
The Geocoding
package comes with support for other services other than
Microsoft, but this is the one we will use in this lesson. Each of the geocoding
systems requires an account and an API key. Microsoft's sign up process is one
of the easiest, and we'll choose that to proceed. To sign up for a key, follow
these procedures
Similar to our JWT_KEY
we will have to add a secret for this API. We'll call
the secret BING_MAPS_KEY
and access it in our RestaurantsController
:
To save the key in secrets:
dotnet user-secrets set "BING_MAPS_KEY" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Where "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
is the key
you generated at Microsoft.
NOTE: If you are going to deploy this with Heroku, you'll need to run
heroku config:set BING_MAPS_KEY="xxxx"
with your specific key in place ofxxxx
at least once before you deploy.
To access the key from the controller:
private readonly string BING_MAPS_KEY;// Constructor that receives a reference to your database context// and stores it in _context_ for you to use in your API methodspublic RestaurantsController(DatabaseContext context, IConfiguration config){_context = context;BING_MAPS_KEY = config["BING_MAPS_KEY"];}
Now that we have added this library and setup an API key, let's add some code to
PostRestaurant
just before restaurant.UserId = GetCurrentUserId();
// Create a new geocodervar geocoder = new BingMapsGeocoder(BING_MAPS_KEY);// Request this address to be geocoded.var geocodedAddresses = await geocoder.GeocodeAsync(restaurant.Address);// ... and pick out the best address sorted by the confidence levelvar bestGeocodedAddress = geocodedAddresses.OrderBy(address => address.Confidence).LastOrDefault();// If we have a best geocoded address, use the latitude and longitude from that resultif (bestGeocodedAddress != null){restaurant.Latitude = bestGeocodedAddress.Coordinates.Latitude;restaurant.Longitude = bestGeocodedAddress.Coordinates.Longitude;}
Let's add some restaurants to our database and see what results we get for
geocoded addresses. Enter some restaurants along with addresses you know and
then check, using pgcli
that there are values for latitude
and longitude
Let's also update our exampledata.sql
to add geocoded locations for our
example restaurants
INSERT INTO "Restaurants" ("Name", "Description", "Address", "Telephone", "Latitude", "Longitude", "UserId") VALUES ('Thoughtbeat', 'Inverse zero administration benchmark', '07 Meadow Vale Drive', '314-651-9791', 27.7970127, -82.6403897, 1);INSERT INTO "Restaurants" ("Name", "Description", "Address", "Telephone", "Latitude", "Longitude", "UserId") VALUES ('Dabtype', 'Organized stable firmware', '7 Miller Park', '523-760-6681', 27.7970543, -82.6557106, 2);INSERT INTO "Restaurants" ("Name", "Description", "Address", "Telephone", "Latitude", "Longitude", "UserId") VALUES ('Topdrive', 'Object-based interactive application', '65 Eliot Lane', '650-993-7074', 27.7833108, -82.7159637, 1);INSERT INTO "Restaurants" ("Name", "Description", "Address", "Telephone", "Latitude", "Longitude", "UserId") VALUES ('Avaveo', 'Persistent zero defect process improvement', '2 Clarendon Junction', '715-663-5265', 27.7717197, -82.6522627, 2);