C# / .NET Quickstart
Server-side: tile proxy, geocoding. .NET 8+.
Project setup
bash
dotnet add package System.Net.Http.JsonGeocoding client
csharp
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
public record GeocodeItem(
double Lat,
double Lng,
string Label,
[property: JsonPropertyName("confidence")] double Confidence,
string Type
);
public sealed class MapsForDevsClient
{
private const string Base = "https://api.mapsfordevs.com";
private readonly HttpClient _http;
public MapsForDevsClient(string apiKey, HttpClient? http = null)
{
_http = http ?? new HttpClient();
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
_http.Timeout = TimeSpan.FromSeconds(10);
}
public async Task<IReadOnlyList<GeocodeItem>> GeocodeAsync(string query, string? country = null, int limit = 5)
{
var url = $"{Base}/geocode/forward?q={Uri.EscapeDataString(query)}&limit={limit}";
if (country is not null) url += $"&country={country}";
var resp = await _http.GetFromJsonAsync<GeocodeResponse>(url)
?? throw new Exception("empty response");
if (!resp.Ok) throw new Exception(resp.Error ?? "mfd error");
return resp.Items ?? Array.Empty<GeocodeItem>();
}
private record GeocodeResponse(
bool Ok,
IReadOnlyList<GeocodeItem>? Items,
string? Error
);
}Tile proxy (ASP.NET Core minimal API)
csharp
using System.Security.Cryptography;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient("mfd", c =>
{
c.BaseAddress = new Uri("https://tiles.mapsfordevs.com");
});
var app = builder.Build();
app.MapGet("/tiles/{z:int}/{x:int}/{y:int}.pbf",
async (int z, int x, int y, IHttpClientFactory factory) =>
{
var key = Environment.GetEnvironmentVariable("MFD_SRV_KEY")!;
var secret = Environment.GetEnvironmentVariable("MFD_SRV_SECRET")!;
var path = $"/tiles/{z}/{x}/{y}.pbf";
var ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var sig = Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes($"GET\n{path}\n{ts}"))).ToLowerInvariant();
var http = factory.CreateClient("mfd");
var req = new HttpRequestMessage(HttpMethod.Get, path);
req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", key);
req.Headers.Add("X-MFD-Timestamp", ts);
req.Headers.Add("X-MFD-Signature", sig);
var upstream = await http.SendAsync(req);
var bytes = await upstream.Content.ReadAsByteArrayAsync();
return Results.File(bytes, "application/x-protobuf");
});
app.Run();