Mitc.Integrations.CensusGeocoder 2.0.0

Mitc.Integrations.CensusGeocoder

A lightweight client over the US Census Bureau geocoder's Find Locations service. Supply one or more addresses, get back coordinates.

Scope

  • Find Locations — address in, coordinates out, plus parsed address components (single lookups) and a raw-response escape hatch.
  • Distance & route planning — great-circle distance between coordinates, and a brute-force shortest-route optimizer for small stop sets.
  • Not covered: Find Geographies (census tract/block lookups), reverse geocoding, and LUCA services.

Usage

services.AddCensusGeocoder();

// Single address
Result<GeocodeMatch> result = await geocoder.GeocodeAsync(
    CensusAddress.OneLine("4600 Silver Hill Rd, Washington, DC 20233"));

// On a successful match, the parsed components are available:
// result.Value.AddressComponents.StreetName, .City, .State, .Zip, ...

// Batch — keyed by your own id (int, long, string, or Guid)
var addresses = new Dictionary<int, CensusAddress>
{
    [1] = CensusAddress.Parsed("4600 Silver Hill Rd", "Washington", "DC", "20233"),
};
IReadOnlyDictionary<int, Result<BatchGeocodeMatch>> results = await geocoder.GeocodeBatchAsync(addresses);

Raw responses

Need a field the typed model doesn't expose, or want to inspect exactly what the geocoder returned? Reach for the raw methods. They return the unparsed body as a string and do not throw on a malformed body. (An HTTP error status — 4xx/5xx — still throws HttpRequestException, the same as the parsed methods.)

// Single lookup — raw JSON, for any outcome (match / tie / no-match).
string json = await geocoder.GetRawResponseAsync(
    CensusAddress.OneLine("4600 Silver Hill Rd, Washington, DC 20233"));

// Batch — raw CSV for the whole upload. The optional formatId controls how each
// key is written so response rows correlate to your ids (defaults to invariant ToString).
string csv = await geocoder.GetRawBatchResponseAsync(addresses);

The single endpoint returns JSON; the batch endpoint returns CSV. Either way it's a string — the batch (CSV) response carries no parsed address components, which is why BatchGeocodeMatch has none while GeocodeMatch does.

Upgrading from 1.x

2.0.0 splits the batch result type. GeocodeBatchAsync now returns IReadOnlyDictionary<TId, Result<BatchGeocodeMatch>> instead of Result<GeocodeMatch>. The batch (CSV) path has no parsed components, so BatchGeocodeMatch exposes only MatchedAddress and Coordinates.AddressComponents is available only on the single-lookup GeocodeMatch. Single-address calls are otherwise unchanged; the new AddressComponents property and the raw methods are additive.

Distance & route planning

All coordinate math is pure and synchronous — no API calls, no DI.

// Great-circle distance between two coordinates
Distance d = a.Coordinates.DistanceTo(b.Coordinates);
double miles = d.Miles;

// Shortest order to visit stops from a distribution center (origin).
// Stops are keyed by your own id; the plan returns those ids in visiting order.
// Capped at RoutePlanner.MaxStops (10) — the search is factorial in the stop count.
var stops = new Dictionary<int, Coordinates>
{
    [1] = stop1.Coordinates,
    [2] = stop2.Coordinates,
};
RoutePlan<int> plan = RoutePlanner.FindShortestRoute(origin, stops, returnToOrigin: true);
// plan.Order          -> ids in optimal visiting sequence
// plan.TotalDistance  -> Distance for the whole route

Result statuses

The Census three-way outcome is mapped onto Mitc.Support.Results.ResultStatus:

Census outcome ResultStatus Notes
Single match Success Value carries the matched address and coordinates.
No match NotFound The geocoder reported no match.
Tie (multiple matches) Conflict Address is well-formed but ambiguous; closest fit, as the enum has no "ambiguous" member.
No row returned (batch only) Invalid The geocoder never answered for that id — distinct from a genuine no-match.

No packages depend on Mitc.Integrations.CensusGeocoder.

Version Downloads Last updated
2.1.0 0 6/25/2026
2.0.0 0 6/25/2026
1.2.1 0 6/23/2026