IPGeoTrace.Client.AspNetCore
0.0.1
dotnet add package IPGeoTrace.Client.AspNetCore --version 0.0.1
NuGet\Install-Package IPGeoTrace.Client.AspNetCore -Version 0.0.1
<PackageReference Include="IPGeoTrace.Client.AspNetCore" Version="0.0.1" />
<PackageVersion Include="IPGeoTrace.Client.AspNetCore" Version="0.0.1" />
<PackageReference Include="IPGeoTrace.Client.AspNetCore" />
paket add IPGeoTrace.Client.AspNetCore --version 0.0.1
#r "nuget: IPGeoTrace.Client.AspNetCore, 0.0.1"
#:package IPGeoTrace.Client.AspNetCore@0.0.1
#addin nuget:?package=IPGeoTrace.Client.AspNetCore&version=0.0.1
#tool nuget:?package=IPGeoTrace.Client.AspNetCore&version=0.0.1
IPGeoTrace ASP.NET Core Integration
ASP.NET Core integration for the IPGeoTrace IP geolocation API, built on the IPGeoTrace.Client package.
Sign up and grab your API key at app.ipgeotrace.com.
Install
dotnet add package IPGeoTrace.Client.AspNetCore
Targets net8.0.
Register the client
One line in Program.cs:
builder.Services.AddIpGeoTrace(builder.Configuration["IpGeoTrace:ApiKey"]!);
That is all the setup there is. Every setting is optional and covered in Configuration below.
From here you have two independent ways to use the library. The middleware is optional. Pick whichever fits, or use both.
Option 1: Use the client directly
Inject IIpGeoTraceClient into any controller or service and resolve whatever IP you supply:
a signup form, a webhook payload, a stored audit log. Where the IP comes from is entirely your
call. Nothing about this touches the request pipeline, and no UseIpGeoTrace call is needed.
Screen new signups for datacenter IPs and country mismatches:
public sealed class SignupScreening(IIpGeoTraceClient geo)
{
public async Task<bool> NeedsReviewAsync(string signupIp, string billingCountry, CancellationToken ct)
{
var result = await geo.ResolveAsync(signupIp, ct);
if (!result.IsSuccess)
return false;
var fromDatacenter = result.Value.Asn?.Type == "hosting";
var countryMismatch = result.Value.Country?.Code is { } code && code != billingCountry;
return fromDatacenter || countryMismatch;
}
}
Enrich a page of audit records in one round trip with a batch lookup:
var batch = await geo.ResolveBatchAsync(logins.Select(l => l.IpAddress), ct);
if (batch.IsSuccess)
foreach (var item in batch.Value.Results)
report.Add(item.Ip, item.Country?.Name, item.Asn?.Name);
See the IPGeoTrace.Client README for the full client documentation.
Option 2: Resolve the caller automatically
This is what this package adds: middleware that determines the caller's IP, resolves it once
per request, and hands you the result anywhere via HttpContext.GetGeo(). No IP handling in
your code at all.
Add it after UseRouting. Endpoint metadata such as [SkipGeo] is only visible to the
middleware once routing has run:
var app = builder.Build();
app.UseRouting();
app.UseIpGeoTrace();
app.MapControllers();
Show prices in the visitor's currency:
[HttpGet("checkout")]
public IActionResult Checkout()
{
var geo = HttpContext.GetGeo();
var currency = geo.IsResolved ? geo.Value.Country?.Currency ?? "USD" : "USD";
return Ok(_catalog.PricedIn(currency));
}
Route the visitor to the nearest warehouse from a minimal API:
app.MapGet("/shipping-estimate", (HttpContext http) =>
{
return http.GetGeo().TryGetValue(out var visitor)
? Results.Ok(Warehouses.NearestTo(visitor.Location?.Latitude, visitor.Location?.Longitude))
: Results.Ok(Warehouses.Default);
});
GeoLookup.Status tells you exactly what happened:
Resolved:Valuecarries the data, andFromCachesays whether an API call was made.Skipped: the caller's address was missing, invalid, private, link-local, or loopback, so no API call was made.Failed:Errorcarries the reason, such asrate_limitedorquota_exceeded.NotAttempted: the middleware did not run for this request, the endpoint opted out, orShouldResolvereturnedfalse.
GetGeo() is always safe to call. It never throws for a missing lookup and reports
NotAttempted when the middleware is not registered.
Skipping endpoints
Health checks, metrics, and internal endpoints should not spend lookups. Opt them out with the attribute:
[HttpGet("health")]
[SkipGeo]
public IActionResult Health() => Ok();
with the minimal API convention:
app.MapGet("/metrics", () => Results.Ok()).SkipGeo();
or centrally with a predicate:
app.UseIpGeoTrace(options =>
{
options.ShouldResolve = context => !context.Request.Path.StartsWithSegments("/internal");
});
Choosing the caller's IP
By default the middleware uses Connection.RemoteIpAddress. Behind a proxy or load balancer,
configure the standard forwarded-headers middleware before UseIpGeoTrace instead of parsing
headers yourself:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor
});
For full control, supply your own selector:
app.UseIpGeoTrace(options =>
{
options.IpAddressSelector = context => context.Connection.RemoteIpAddress?.ToString();
});
Private, link-local, and loopback addresses (including IPv4-mapped IPv6 forms) are detected locally and skipped without an API call or quota usage.
Configuration
All settings live on the AddIpGeoTrace options callback. Each one is optional.
Caching
Off by default. Turn it on and repeat lookups of the same IP are served from memory: no API call, no latency, and nothing counted against your monthly quota. Returning visitors become free after their first request.
builder.Services.AddIpGeoTrace(apiKey, options =>
{
options.CacheEnabled = true;
});
Only successful lookups are cached, never errors. Batch calls share the same cache, so only the misses are sent to the API.
Cache lifetime
How long a cached lookup stays valid. The default is 5 minutes.
options.CacheTtl = TimeSpan.FromHours(6);
Your own cache store
Supply any IGeoCache implementation (Redis, distributed cache, anything) and caching turns on
automatically. If you register an IGeoCache in the container instead, it is picked up without
any option at all. A throwing store never breaks a lookup; the client falls back to calling the
API directly.
options.Cache = new RedisGeoCache(connection);
Timeout
Per-request timeout. The default is 10 seconds.
options.Timeout = TimeSpan.FromSeconds(3);
Retries
Rate limits (429) and outages (503) are retried automatically, honoring the API's Retry-After
header. The default is 2 retries. Set it to 0 if you chain your own resilience handler (for
example Polly) on the IHttpClientBuilder that AddIpGeoTrace returns, so requests are not
retried twice.
options.MaxRetries = 0;
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- IPGeoTrace.Client (>= 0.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1 | 119 | 7/2/2026 |