Skip to content

maximn/google-maps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

461 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

NuGet Downloads NuGet Version Build Status CodeQL OpenSSF Scorecard License: BSD-2-Clause .NET

Release history: see CHANGELOG.md.

GoogleMapsApi

A friendly, strongly-typed .NET wrapper for the Google Maps Web Services APIs — Geocoding, Routes, Directions, Distance Matrix, Elevation, Time Zone, Places, Address Validation, and Static Maps. Multi-framework (net10.0, net8.0, netstandard2.0 — the latter still covers .NET Framework 4.6.1+), async-first, and battle-tested with 2M+ downloads on NuGet.

Supported APIs

API Description
Geocoding Convert between addresses and geographic coordinates
Routes Modern route planning — real-time traffic, eco-routing, toll calc, two-wheeled vehicles (replaces Directions)
Directions Legacy route planning between two points with multiple travel modes
Distance Matrix Travel time and distance between multiple origins/destinations
Elevation Elevation data for individual locations or paths
Time Zone Time zone information for any coordinate
Places (New) Modern Places API — Text Search, Nearby Search, Place Details, Autocomplete, Place Photos
Address Validation Validate a postal address with component-level confirmation; USPS CASS for US/PR
Static Maps Generate URLs for static map images with markers, paths, and styles

Why this vs Google's official SDKs

Google's official .NET packages (e.g. Google.Maps.Routing.V2, Google.Maps.Places.V1) are auto-generated from gRPC service definitions — they're verbose, split across many packages, and feel like protobuf instead of .NET. GoogleMapsApi is a single, idiomatic NuGet package: one install, async-first, multi-target (modern .NET through legacy .NET Framework), with hand-crafted request/response types that read like normal C#.

Installation

Install via NuGet Package Manager:

Install-Package GoogleMapsApi

Or via .NET CLI:

dotnet add package GoogleMapsApi

Looking for runnable examples? See samples/ — console, ASP.NET Core minimal API, and Blazor Server.

Quickstart

API Key Configuration

You can configure your Google Maps API key in several ways:

// Option 1: Set API key per request
DirectionsRequest directionsRequest = new DirectionsRequest()
{
    Origin = "NYC, 5th and 39",
    Destination = "Philadelphia, Chestnut and Walnut",
    ApiKey = "your-google-maps-api-key"
};

// Option 2: Set globally via app.config/appsettings.json (see wiki for details)

For more configuration options and detailed guides, see the wiki. Full API reference is published at maximn.github.io/google-maps.

Code Examples

Important

The static GoogleMaps facade was removed in 2.0.0, along with the legacy Places API (use Places (New)). Use the instance-based IGoogleMapsClient / GoogleMapsClient instead — construct it with an HttpClient (directly or via IHttpClientFactory / dependency injection). See Instance-based client below. Upgrading from 1.x? See the 2.0 migration guide.

Basic Usage (async-first)

using GoogleMapsApi;
using GoogleMapsApi.Entities.Common;
using GoogleMapsApi.Entities.Directions.Request;
using GoogleMapsApi.Entities.Directions.Response;
using GoogleMapsApi.Entities.Geocoding.Request;
using GoogleMapsApi.Entities.Geocoding.Response;
using GoogleMapsApi.StaticMaps;
using GoogleMapsApi.StaticMaps.Entities;

// Create a client backed by an HttpClient (reuse a single instance; IHttpClientFactory friendly)
using var http = new HttpClient();
var maps = new GoogleMapsClient(http, new GoogleMapsClientOptions { ApiKey = "your-google-maps-api-key" });

// Directions
DirectionsRequest directionsRequest = new DirectionsRequest()
{
    Origin = "NYC, 5th and 39",
    Destination = "Philadelphia, Chestnut and Walnut",
};

// Async call (recommended)
DirectionsResponse directions = await maps.Directions.QueryAsync(directionsRequest);
Console.WriteLine(directions);

// Geocode
GeocodingRequest geocodeRequest = new GeocodingRequest()
{
    Address = "new york city",
};
GeocodingResponse geocode = await maps.Geocode.QueryAsync(geocodeRequest);
Console.WriteLine(geocode);

// Static maps API - get static map of with the path of the directions request
StaticMapsEngine staticMapGenerator = new StaticMapsEngine();

//Path from previos directions request
IEnumerable<Step> steps = directions.Routes.First().Legs.First().Steps;
// All start locations
IList<ILocationString> path = steps.Select(step => step.StartLocation).ToList<ILocationString>();
// also the end location of the last step
path.Add(steps.Last().EndLocation);

string url = staticMapGenerator.GenerateStaticMapURL(new StaticMapRequest(new Location(40.38742, -74.55366), 9, new ImageSize(800, 400))
{
    Pathes = new List<GoogleMapsApi.StaticMaps.Entities.Path>(){ new GoogleMapsApi.StaticMaps.Entities.Path()
    {
            Style = new PathStyle()
            {
                    Color = "red"
            },
            Locations = path
    }}
});
Console.WriteLine("Map with path: " + url);

Routes API (modern replacement for Directions)

The Routes API is Google's modern replacement for the Directions API — it supports real-time traffic, eco-routing, toll calculation, two-wheeled vehicles, and route alternatives. Unlike Directions, it requires a field mask to constrain the response. A sensible default is pre-populated; tighten it to reduce response size and cost.

using GoogleMapsApi;
using GoogleMapsApi.Entities.Routes.Request;

using var http = new HttpClient();
var maps = new GoogleMapsClient(http, new GoogleMapsClientOptions { ApiKey = "your-google-maps-api-key" });

var request = new RoutesRequest
{
    Origin = Waypoint.FromAddress("San Francisco, CA"),
    Destination = Waypoint.FromAddress("Mountain View, CA"),
    TravelMode = RoutesTravelMode.Drive,
    RoutingPreference = RoutingPreference.TrafficAware,
    // FieldMask defaults to a Directions-equivalent shape; override to slim the response.
};

var response = await maps.Routes.QueryAsync(request);
var route = response.Routes![0];
Console.WriteLine($"{route.DistanceMeters} m, {route.DurationSeconds} s");

Instance-based client (IHttpClientFactory-friendly)

GoogleMapsClient is the instance-based entry point that accepts an injected HttpClient. This is the standard pattern for ASP.NET Core, minimal APIs, and worker services — it plays nicely with IHttpClientFactory, per-instance event handlers, and an ambient API key that is auto-filled into requests when not set explicitly.

The companion package GoogleMapsApi.Extensions.DependencyInjection provides an AddGoogleMaps extension that registers the client through IHttpClientFactory and binds options in one call:

dotnet add package GoogleMapsApi.Extensions.DependencyInjection
// Register once at startup
services.AddGoogleMaps(options => options.ApiKey = "your-google-maps-api-key");
// …or bind from configuration (e.g. a "GoogleMaps" section in appsettings.json):
services.AddGoogleMaps(builder.Configuration.GetSection("GoogleMaps"));

// Inject and use
public class GeocodingService(IGoogleMapsClient maps)
{
    public Task<GeocodingResponse> LookupAsync(string address)
        => maps.Geocode.QueryAsync(new GeocodingRequest { Address = address });
}

AddGoogleMaps returns an IHttpClientBuilder, so you can chain resilience and other HttpClient configuration — e.g. .AddStandardResilienceHandler() from Microsoft.Extensions.Http.Resilience.

Prefer not to take the extra package? The core library still works with hand-wired DI:

services.AddHttpClient<IGoogleMapsClient, GoogleMapsClient>();
services.AddSingleton(new GoogleMapsClientOptions { ApiKey = "your-google-maps-api-key" });

Without DI:

using var http = new HttpClient();
var maps = new GoogleMapsClient(http, new GoogleMapsClientOptions { ApiKey = "your-key" });

var result = await maps.Directions.QueryAsync(new DirectionsRequest { Origin = "NYC", Destination = "DC" });

Per-instance events (no global state):

maps.Geocode.OnUriCreated += uri => uri;          // inspect/rewrite outgoing URI
maps.Geocode.OnRawResponseReceived += bytes => { }; // tap raw JSON

Synchronous Usage

The API is async-first. When you must call from a synchronous context, block on the task (prefer QueryAsync whenever possible):

DirectionsResponse directions = maps.Directions.QueryAsync(directionsRequest).GetAwaiter().GetResult();
Console.WriteLine(directions);

If this library saved you time, please ⭐ the repo — it helps others find it.