Address Standardization & Validation – Technical Details
Back to DemoHigh-Level System Overview
- Purpose: Parse freeform address text into normalized components, then validate the result through ArcGIS forward geocoding.
- Business problem: Demonstrates backend address quality workflows used before routing, geocoding, data enrichment, CRM deduplication, or spatial analytics.
- Architecture: Razor Page form → versioned ASP.NET Core API →
IAddressStandardizationService→ regex/suffix normalization → ArcGISfindAddressCandidatesvalidation. - Technologies: .NET 10, Razor Pages, vanilla JavaScript, typed
HttpClient, Polly resilience,System.Text.RegularExpressions, shared ArcGIS wire models. - Deployment model: Runs with the Portfolio web application and uses environment-driven configuration for ArcGIS resilience and service behavior.
Frontend Architecture
The front end is a Razor Page enhanced by wwwroot/js/AddressStandardization/app.js. It provides two workflows: parse-only for deterministic normalization and validate for ArcGIS-backed candidate scoring.
- Page structure: Bootstrap cards separate raw input, parsed components, matched address, score, and confidence tier.
- API communication: The page uses shared route constants for
/api/v1/addresses/parseand/api/v1/addresses/validate. - State management: Client state is local to the form; the source of truth for parsing and validation remains server-side to keep business logic testable.
- UX decisions: Confidence badges make uncertainty visible instead of presenting geocoding as a binary success/failure outcome.
API Layer
- Controller:
AddressStandardizationControlleris versioned at/api/v1/addressesand is[AllowAnonymous]. - Endpoints:
POST /api/v1/addresses/parsereturnsAddressParsedDto;POST /api/v1/addresses/validatereturnsAddressValidationResultDto. - Request contract: Both endpoints accept
AddressParseRequestDtowithRawAddress. - Validation: The controller rejects missing input, and the service repeats null/empty validation as the business boundary.
- Error handling:
ArgumentExceptionmaps to 400; an open ArcGIS circuit returns 503 with retry guidance. - OpenAPI: XML comments and
[ProducesResponseType]attributes make the parse and validate contracts discoverable through the API explorer.
Services and Business Logic
- Service boundary:
AddressStandardizationServiceowns normalization, suffix expansion, component extraction, state validation, confidence scoring, ArcGIS validation, and fallback logic. - Parsing workflow: The service normalizes whitespace/case, expands suffixes such as
SttoStreet, extracts house number, street, unit, city, state, and ZIP, then computesParseConfidence. - Validation workflow: The standardized address is sent to ArcGIS
findAddressCandidates; if the best candidate is below 75, the service retries with a broader City + State + ZIP query. - Confidence model: ArcGIS score maps to
ConfidenceTier: High at 90+, Medium at 75+, Low at 50+, otherwise Unresolved. - Reusable integration: The service shares
ArcGisGeocodeResponse,ArcGisGeocodeCandidate, andArcGisLocationwith batch geocoding because both consume the same ArcGIS endpoint.
Data Access Layer
This workflow is computational and integration-focused; it does not persist parsed addresses to PostgreSQL. That keeps the service stateless and appropriate for public validation calls.
- Relational data: No EF Core repository is required because there are no persisted entities for parse or validation requests.
- Wire models: ArcGIS response classes live in
Portfolio.Common/ArcGiswith explicit[JsonPropertyName]attributes to protect deserialization from naming mismatches. - Caching: No dedicated address-standardization Redis cache is currently applied; repeated validation relies on ArcGIS resilience policies rather than stored results.
- Scalability: Stateless service logic makes horizontal scaling straightforward; future caching could key on normalized address text if validation traffic becomes repetitive.
Infrastructure and Deployment
- Hosting: Runs as part of the same Render-hosted ASP.NET Core application as the other portfolio APIs.
- Configuration: ArcGIS timeout, retry, and circuit breaker behavior is configured through the typed
HttpClientregistration inProgram.cs. - Shared Redis infrastructure: This stateless parser does not store results in Redis, but the hosting application uses Redis for batch geocoding job state, geocoding caches, and production Data Protection keys when configured.
- Observability: Controller logging records upstream circuit-breaker failures; unexpected exceptions flow through centralized middleware.
- Container/cloud readiness: Because the workflow is stateless, it works well in Docker, Kubernetes, Azure Container Apps, AKS, or any horizontally scaled container platform.
- Secrets: No hard-coded credentials are required for the sample ArcGIS endpoint; production geocoding providers would move API keys to environment variables or a secret store.
Engineering Decisions and Tradeoffs
- Regex-based parsing: Keeps the implementation transparent and dependency-light, but does not match the coverage of a specialized address parsing library.
- Server-side parsing: Centralizes business rules and testability rather than duplicating parsing logic in JavaScript.
- Fallback query: Improves recovery for noisy addresses but may produce less specific matches; the confidence tier communicates that uncertainty.
- Future improvements: Add provider abstraction, per-country parsing strategies, normalized-address caching, rate limiting, telemetry by failure reason, and human-review queues for unresolved addresses.
Interview Discussion Points
- How would you separate deterministic parsing confidence from geocoder match confidence?
- When would you add caching to address validation, and what would the cache key include?
- How would you internationalize the parser without creating unmaintainable regex rules?
- What observability would help distinguish bad input from upstream geocoder quality issues?
- How would this service fit into a larger batch enrichment or ETL pipeline?