C# / .NET SDK
Geocoding from C#. Install, authenticate, and make your first call.
The .NET SDK includes typed requests, normalized results, and optional Google/HERE fallbacks. It uses HttpClient and System.Text.Json and has no third-party runtime dependencies.
Installation
Requires .NET 8 or later. The package is not yet published to NuGet. Add a local project reference from your application directory. Replace the path with your checkout:
dotnet add reference /path/to/pelias/sdk/dotnet/src/AffordableGeoApis/AffordableGeoApis.csproj
Quick start
Create a client with your deployment URL and API key, then submit an address:
using AffordableGeoApis;
using var client = new GeocodingClient(new ClientOptions
{
BaseUrl = Environment.GetEnvironmentVariable("GEOCODING_BASE_URL")!,
ApiKey = Environment.GetEnvironmentVariable("GEOCODING_API_KEY")!,
});
var response = await client.GeocodeAsync(new AddressRequest(
Street: "11 Wall Street",
City: "New York",
State: "NY",
Zip: "10005"
));
foreach (var result in response.Results)
{
Console.WriteLine($"{result.Label}: {result.Lat}, {result.Lon}");
}
Results is a list of address candidates. Check that it is nonempty before selecting a candidate. A no-match request succeeds with an empty list.
Examples use top-level statements and the implicit System imports enabled by current .NET console templates. In a class-based application, await SDK calls inside an async method.
Authentication
Set the primary URL and key in your backend environment:
export GEOCODING_BASE_URL='http://localhost:8000'
export GEOCODING_API_KEY='YOUR_API_KEY'
Pass both values to the constructor as shown above. The SDK sends the key in the apikey header. Use your assigned HTTPS URL in production; the base URL excludes /v1/geocode. Keep all provider keys on your backend.
Available methods
| Method | Use |
|---|---|
client.GeocodeAsync(request, cancellationToken) | Find coordinates for a street address |
client.SearchAsync(request, cancellationToken) | Find addresses and places from one line of free text |
client.ReverseGeocodeAsync(request, cancellationToken) | Find address candidates for coordinates |
client.AutocompleteAsync(request, cancellationToken) | Suggest addresses for partial text and a required country |
client.ResolveAutocompleteAsync(suggestion, cancellationToken) | Resolve the selected suggestion into one address |
The cancellation token is optional. Geocode, search, and reverse geocode return Task<GeocodingResponse>. Autocomplete returns Task<AutocompleteResponse>; resolution returns Task<GeocodingResult>. See the client reference for request and result types.
Common operations
Free-text search
var response = await client.SearchAsync(new SearchRequest(
Q: "11 Wall Street, New York, NY",
Country: "US",
Limit: 5
));
foreach (var result in response.Results)
{
Console.WriteLine($"{result.Label}: {result.Lat}, {result.Lon}");
}
Search accepts one line of text, such as an address, place name, city, or ZIP code, and returns matches of any type. Q is required (1 to 256 characters). Country restricts results, Near: new Point(lat, lon) prefers nearby results, and Limit is 1 to 40 (default 10). Use geocode when the address is already split into fields. See search.
Address autocomplete
var response = await client.AutocompleteAsync(new AutocompleteRequest(
Q: "11 Wall",
Country: "US",
Limit: 5
));
if (response.Suggestions.Count > 0)
{
var address = await client.ResolveAutocompleteAsync(response.Suggestions[0]);
Console.WriteLine($"{address.Label}: {address.Lat}, {address.Lon}");
}
Keep the suggestion object unchanged until selection. Resolution calls only its provider and does not run fallback selection or use fallback budgets/circuits. See autocomplete.
Reverse geocoding
var response = await client.ReverseGeocodeAsync(new ReverseRequest(
Lat: 40.7074,
Lon: -74.0113
));
foreach (var result in response.Results)
{
Console.WriteLine(result.Label);
}
Excluding a data source
var response = await client.GeocodeAsync(new AddressRequest(
Street: "11 Wall Street",
City: "New York",
ExcludeSources: ["osm"]
));
Exclusions affect primary candidates only. ExcludeSources maps to the HTTP field exclude_sources. See data sources.
C# types
AddressRequest request = new(Street: "11 Wall Street", City: "New York");
GeocodingResponse response = await client.GeocodeAsync(request);
Request and response properties use PascalCase. All SDK types are in the AffordableGeoApis namespace.
Configuration
Provider fallbacks
Add the providers you want to call, in order:
using var client = new GeocodingClient(new ClientOptions
{
BaseUrl = Environment.GetEnvironmentVariable("GEOCODING_BASE_URL")!,
ApiKey = Environment.GetEnvironmentVariable("GEOCODING_API_KEY")!,
ConfidenceThreshold = 0.8,
MaxFallbackRequests = 1000,
Fallbacks = [
new("google", Environment.GetEnvironmentVariable("GOOGLE_MAPS_API_KEY")!),
new("here", Environment.GetEnvironmentVariable("HERE_API_KEY")!),
],
});
The first nonempty backup wins when primary has no results, low confidence, or an eligible outage. Backups are off by default. A request with Country: "GB" skips primary and uses configured backups. See fallback policy for triggers, budgets, and circuit breakers.
Error handling
try
{
await client.GeocodeAsync(new AddressRequest("11 Wall Street", City: "New York"));
}
catch (GeocodingError error)
{
Console.Error.WriteLine($"{error.Code} {error.Status}: {error.Message}");
foreach (var attempt in error.Attempts)
{
Console.Error.WriteLine($"{attempt.Provider}: {attempt.Outcome}");
}
}
Primary HTTP 4xx and malformed responses do not trigger fallback. Terminal provider errors include the complete attempt history. Caller cancellation throws OperationCanceledException separately.
Timeouts and cancellation
Each provider request times out after ten seconds by default. Set constructor TimeoutMs to change it. To bound the whole provider chain:
using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(15));
var response = await client.GeocodeAsync(
new AddressRequest("11 Wall Street", City: "New York"),
deadline.Token
);
Pass a CancellationToken for caller-controlled cancellation. Cancellation throws OperationCanceledException and stops the chain.
Retries
The SDK does not retry automatically. If your application retries, bound the attempts and use backoff. Each call can consume primary and backup usage.
Raw provider response
if (response.ProviderResponse is { } body)
{
Console.WriteLine(body.GetRawText());
}
ProviderResponse contains the full parsed body of the selected Google/HERE response as a nullable JsonElement. It is null for primary results. To serialize the normalized response with camelCase fields, use JsonSerializer.Serialize(response, GeocodingClient.JsonOptions) from System.Text.Json.
Reuse a client to share fallback budgets and circuits. Dispose it when your application shuts down; using var disposes it at the end of its scope.
For partial address entry, see address autocomplete.