In this article, we will learn how to find the latitude and longitude of a location in C# using the Google Maps Geocoding API. We’ll introduce two different methods for obtaining the coordinates: using the GoogleMaps.LocationServices NuGet package, which simplifies the process but can be less flexible, and using HttpClient directly, which provides us more control over HTTP requests and responses.

To download the source code for this article, you can visit our GitHub repository.

So, let’s begin.

Get an API Key and Configure the Project

First, to get the latitude and longitude of an address, we’ll need to get an API key from Google. To do this, we visit Google’s developer documentation for instructions on getting one. It’s also important to secure our API key to ensure no one else can use it. To accomplish this, we will store our API key using the Secret Manager tool to keep it safe.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
To learn more about secret management, check out our article Tools and Best Practices for Secret Management in .NET.

Next, let’s define an address for our testing:

var address = "Miami, Florida";

Now, let’s create a simple console application and set up our ConfigurationBuilder:

public class Program
{
    static async Task Main(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .AddUserSecrets<Program>();
        var configuration = builder.Build();
        var apiKey = configuration["Secret:MyApiKey"];

        if (string.IsNullOrEmpty(apiKey))
        {
            Console.WriteLine("API key not found.");

            return;
        }
    }
}

This configuration builder helps us get the API key from the secret manager. Here, we initialize a ConfigurationBuilder, and then add user secrets to the Program class. We then call Build() to build our configuration. Our configuration object now has the settings from our user secrets.

Next, we retrieve the API key value from the configuration using the key "Secret:MyApiKey" (We can name this whatever we call our API key in the secret manager). Next, we verify that we have successfully loaded our API key (i.e. validate its existence), by ensuring it’s not null or empty.

Now, we can begin getting our coordinates!

Find the Latitude and Longitude of a Location via GoogleMaps.LocationServices NuGet Package

First, we install the GoogleMaps.LocationServices NuGet package:

dotnet add package GoogleMaps.LocationServices

The Google Maps Location Services package allows our app to communicate with Google Maps for location services, which includes getting the latitude and longitude.

We start by defining the model:

public class CustomMapPoint
{
    [Required]
    public double Latitude { get; set; }
    [Required]
    public double Longitude { get; set; }
}

Here, we define a CustomMapPoint class. We will use this class to return a latitude and a longitude in our methods. The [Required] attribute ensures that Longitude and Latitude are provided to help us avoid situations where we have incomplete or incorrect location data.

Implementing the Service

Next, we create an interface that tells our app what a location service should do:

public interface IMapLocationService
{
    Task<CustomMapPoint> GetLatLongFromAddressAsync(string address);
}

Here, the IMapLocationService interface allows us to use different mapping services if needed, not just Google Maps, without changing much of our code. Within our new interface, we define the method GetLatLongFromAddressAsync(), which takes an address as a parameter and asynchronously returns a CustomMapPoint object. 

Now, we wrap Google’s location service into a class that implements our interface:

public class GoogleLocationServiceWrapper : IMapLocationService
{
    private readonly GoogleLocationService _glsContext;

    public GoogleLocationServiceWrapper(string apiKey)
    {
        _glsContext = new GoogleLocationService(apiKey);
    }

    public async Task<CustomMapPoint> GetLatLongFromAddressAsync(string address)
    {
        var location = await Task.Run(() => _glsContext.GetLatLongFromAddress(address)); 

        return new CustomMapPoint() { Latitude = location.Latitude, Longitude = location.Longitude };
    }
}

Here, we declare our class GoogleLocationServiceWrapper which implements the IMapLocationService interface. Then, we declare a private readonly field _glsContext with the type GoogleLocationService. This field will hold an instance of Google’s location service that we’ll use to get the coordinates.

In the constructor, we initialize _glsContext with a new instance of GoogleLocationService passing an API key as a parameter. We do this to authenticate requests to Google’s location service.

We then implement the asynchronous method GetLatLongFromAddressAsync() from our interface. In the method, we use the _glsContext instance to call GetLatLongFromAddress(), passing in our address. We also wrap this call in Task.Run(), making it asynchronous and thus preventing it from blocking the main execution thread. This method then communicates with Google’s location service and returns a location object containing our latitude and longitude values.

Lastly, we create and return a new CustomMapPoint object, setting its Latitude and Longitude properties to the values from the location object.

Getting the Latitude and Longitude

After installing the Google Maps Location Services package, setting up the CustomMapPoint model,  IMapLocationService interface and creating a GoogleLocationServiceWrapper, we can now get our coordinates:

public class LatLongWithNuGet
{
    private readonly IMapLocationService _locationService;

    public LatLongWithNuGet(IMapLocationService locationService)
    {
        _locationService = locationService;
    }

    public async Task<string> GetLatLongWithNuGet(string address)
    {
        try
        {
            var latlong = await _locationService.GetLatLongFromAddressAsync(address);
            
            return $"Address ({address}) is at {latlong.Latitude}, {latlong.Longitude}";
        }
        catch (Exception ex)
        {
            return $"Error retrieving coordinates: {ex.Message}";
        }
    }
}

Here, we create the LatLongWithNuGet class. This class uses a private readonly field for the IMapLocationService, making sure that the service we provided to the class at the start doesn’t change later on.

Then, the class constructor takes an IMapLocationService as the type of parameter, allowing the class to work with any service that follows this interface.

Next, in the GetLatLongWithNuGet method, we try to get the coordinates of an address asynchronously. If the location service successfully finds the address, it returns the coordinates. If not, the catch block catches any errors and returns an error message.

Finally, in Program.cs, we can get the latitude and longitude:

var locationService = new GoogleLocationServiceWrapper(apiKey);
var latLongWithNuGet = new LatLongWithNuGet(locationService);
var coordinatesNuGet = await latLongWithNuGet.GetLatLongWithNuGet(address);

Console.WriteLine(coordinatesNuGet);

First, we create locationService using GoogleLocationServiceWrapper and our API key, connecting us to Google’s location services. Then, we initialize a LatLongWithNuGet instance passing in our locationService object. Finally, we asynchronously retrieve our coordinates by calling the GetLatLongWithNuGet() method on the latLongWithNuGet instance:

Address (Miami, Florida) is at 25.7616798, -80.1917902

Even though we have the latitude and longitude, let’s try one other way of getting the coordinates using HttpClient directly. 

Find the Latitude and Longitude of a Location via HttpClient

Here, we’re using HttpClient to get the latitude and longitude of Miami, Florida by communicating with Google’s Geocoding API. One advantage of using HttpClient directly is that it offers more control and flexibility. Additionally, to better manage HttpClient, we will use the IHttpClientFactory interface.

Setting Up HttpClient for Geocoding

Since we are using IHttpClientFactory, we first add the Microsoft.Extensions.Http package: 

dotnet add package Microsoft.Extensions.Http

This package introduces IHttpClientFactory, which helps us better manage HttpClient instances in our projects. It’s a game-changer for creating and using HttpClient in a way that improves application performance and reliability.

We use IHttpClientFactory because directly instantiating HttpClient can lead to challenges like socket exhaustion and slow performance.

To learn more about IHttpClientFactory, take a look at our other article Using HttpClientFactory in ASP.NET Core Applications.

After we add the package, we can move on to create our LatLongWithHttpClient class:

public class LatLongWithHttpClient : IMapLocationService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly string _apiKey;

    public LatLongWithHttpClient(IHttpClientFactory httpClientFactory, string apiKey)
    {
        _httpClientFactory = httpClientFactory;
        _apiKey = apiKey;
    }
}

Here, in our LatLongWithHttpClient class, we implement the IMapLocationService interface that we created previously. This is to make sure our code is compatible with different mapping services. This class includes private readonly fields _httpClientFactory and _apiKey. _httpClientFactory is used for creating instances of HttpClient for web requests to Google’s Geocoding API. Both fields are private and readonly because they are only needed within this class and shouldn’t change once we initialize them. We then initialize these fields in the constructor.

Creating Our Geocoding Method

Let’s move on to our GetLatLongWithAddressAsync method:

public async Task<CustomMapPoint> GetLatLongFromAddressAsync(string address)
{
    var httpClient = _httpClientFactory.CreateClient("MapsClient");
    var relativeUri = $"maps/api/geocode/json?address={Uri.EscapeDataString(address)}&key={_apiKey}";

    var response = await httpClient.GetAsync(relativeUri);
    response.EnsureSuccessStatusCode();
    var root = await response.Content.ReadFromJsonAsync<JsonElement>();
    var status = root.GetProperty("status").GetString();

   // ... continued after explanation
}

Here, the GetLatLongWithAddressAsync method uses async tasks to find the latitude and longitude using Google’s Geocoding API. We start by using _httpClientFactory.CreateClient("MapsClient") to get an instance of HttpClient that’s set up for mapping services. This instance is assigned to the httpClient variable. The "MapsClient" refers to the settings we define later in Program.cs, which will include the base URL for Google’s Geocoding API. 

After that, we initialize relativeUri with the address and API key.

Then, we send a GET request with httpClient.GetAsync(relativeUri) and wait for the response. After checking for a successful status with response.EnsureSuccessStatusCode(), we parse the JSON response and assign it to the variable root.

If the response status is “OK”, we go through root to get the latitude and longitude:

if (status == "OK")
{
    var location = root.GetProperty("results")[0].GetProperty("geometry").GetProperty("location");
    return new CustomMapPoint
    {
        Latitude = location.GetProperty("lat").GetDouble(),
        Longitude = location.GetProperty("lng").GetDouble()
    };
}
else
{
    throw new Exception($"Error retrieving coordinates: '{status}'.");
}

First, root.GetProperty("results")[0] allows us to access the first item in the “results” array.

Then, .GetProperty("geometry").GetProperty("location") reaches the “location” object, where the geographic data is found, and assigns the data to the location variable.

After that, we create and return a new CustomMapPoint object, setting its Latitude and Longitude properties using location.GetProperty("lat").GetDouble() and location.GetProperty("lng").GetDouble()

However, if the status isn’t “OK”, the method throws an exception.

Getting the Latitude and Longitude of a Location

Finally, in Program.cs, we can get our coordinates:

var services = new ServiceCollection();

services.AddHttpClient("MapsClient", client =>
{
    client.BaseAddress = new Uri("https://maps.googleapis.com/");
});

services.AddSingleton<LatLongWithHttpClient>(provider =>
    new LatLongWithHttpClient(provider.GetRequiredService<IHttpClientFactory>(), apiKey));

var serviceProvider = services.BuildServiceProvider();
var latLongWithHttpClient = serviceProvider.GetRequiredService<LatLongWithHttpClient>();
var coordinatesHttpClient = await latLongWithHttpClient.GetLatLongFromAddressAsync(address);

Console.WriteLine($"Address ({address}) is at {coordinatesHttpClient.Latitude}, {coordinatesHttpClient.Longitude}");

Here, we initialize a new ServiceCollection, which serves as a container for adding and configuring services. It’s where we register dependencies that our application will use.

Then, we register a named instance of HttpClient configured with a base address set to Google’s Geocoding API URL.

Next, we add LatLongWithHttpClient as a singleton service. This means that one instance of LatLongWithHttpClient will be created and used throughout the app’s lifetime. This instance is created using IHttpClientFactory and an apiKey, both fetched from the service collection. IHttpClientFactory is injected to help with the creation of HttpClient instances that are pre-configured with the settings defined earlier (like the base address). This simplifies how our app handles resources and keeps HTTP request settings consistent across the board.

After that, BuildServiceProvider turns the service collection into a service provider that can create and supply the registered services whenever needed.

Once that is set up, we use GetRequiredService<LatLongWithHttpClient>() to fetch the LatLongWithHttpClient instance from the service container. If it’s unavailable, it will throw an exception. 

Lastly, we use the latLongWithHttpClient instance to call GetLatLongFromAddressAsync() with an address. This asynchronous method gets the latitude and longitude of the address and assigns the result to coordinatesHttpClient. The latitude and longitude values are stored as properties of this object, specifically coordinatesHttpClient.Latitude and coordinatesHttpClient.Longitude.

After we run the code, we should see this in the console:

Address (Miami, Florida) is at 25.7616798, -80.1917902

Conclusion

In this article, we covered two methods to find the latitude and longitude of a location in C#. We demonstrated using HttpClient through IHttpClientFactory for direct API calls, and using the GoogleMaps.LocationServices NuGet package.

Both methods interact with the Google Maps Geocoding API but offer different levels of control and simplicity.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!