Compute driving distances¶
GoogleMapsApiServiceProxy is the library's one hand-rolled REST/XML client: it queries the Google Distance Matrix API directly over System.Net.WebRequest, then exposes several distance-computation methods with different single-pair, one-to-many, and error-tolerance behaviors.
| Field | Value |
|---|---|
| Operation ID | OP-WP-09 |
| Trigger | SAIF.Services.Legal.Subpoenas.SubpoenaService, through the constructor-injected IGoogleMapsApiServiceProxy |
| Inputs | Origin and destination address strings (single or multiple) |
| Outputs | A DistanceResults, a list of miles, or an ErrorMessage |
| Primary components | GoogleMapsApiServiceProxy.QueryGoogleApi, GetDataBetweenTwoAddresses, GetMilesBetweenTwoAddresses, GetMilesFromManyToOneAddress, GetMilesFromOneToManyAddresses, GetMilesBetweenMultipleAddresses |
| Entry point | Services/SAIF.Services.Web.Proxies/GoogleMapsApiServiceProxy.cs |
Steps¶
- Construct
GoogleMapsApiServiceProxy(ILogService, IEnvironmentService): guard both services (WP-BR-001), then readgooglemaps.apibaseuriandgooglemaps.apikeyviaGetConfigSetting(WP-BR-020). QueryGoogleApi(origins, destinations)(private): (WP-BR-021)- Build the URL:
{baseuri}distancematrix/xml?units=imperial&language=en&origins=a|b&destinations=c|d&key={apikey}; each address has%3Cbr%3Ereplaced by a space, and addresses are not URL-encoded. - Send a
WebRequestwith a 5000 ms timeout, and load the response as anXDocument.- On failure: log via
ILogService.LogException("GoogleMapsApiServiceProxy", "QueryGoogleApi", "WebRequest", e), then thrownew Exception(e.Message)— the original exception type and stack trace are lost, and the response/stream are not disposed.
- On failure: log via
GetDataBetweenTwoAddresses(o, d):- Query the API (step 2).
- If the first
element/statusis"OK": setMilesfromdistance/value(meters ÷ 1609.34, rounded to 1 decimal — WP-BR-022),Distancefromdistance/text,Timefromduration/text, andSecondsfromduration/value.- If parsing fails: throw
Exception("Google Maps API Service Error - unable to calculate mileage.").
- If parsing fails: throw
- Otherwise: set
ErrorMessageto the status message plus the status; nothing is thrown (WP-BR-023). GetMilesBetweenTwoAddresses(o, d): query the API, then convert the firstdistance/valueto miles; any failure throws the generic mileage error.GetMilesFromManyToOneAddress(origins, destination)/GetMilesFromOneToManyAddresses(origin, destinations): query the API, then take eachelement's distance in miles.- A failing element yields 0 and does not throw (WP-BR-024).
GetMilesBetweenMultipleAddresses(origins, destinations):- If the origin and destination counts differ: throw before any query is sent (WP-BR-025).
- Query the full matrix (step 2).
- For row i, take element i, pairing origin i with destination i (the diagonal).
- A failing element yields 0 (WP-BR-024).
Process flow¶
The following diagram visualizes the shared query path and its two error-handling behaviors (throw vs. error-in-result).
flowchart TD
Start([Distance method invoked]) --> CountCheck{Multi-address:<br>counts equal?}
CountCheck -->|No| Throw1([Throw before querying])
CountCheck -->|Yes / n-a| Build["Build pipe-delimited,<br>non-encoded URL"]
Build --> Web["Send WebRequest<br>(5000 ms timeout)"]
Web -->|Exception| LogThrow["Log via ILogService,<br>throw new Exception(e.Message)"]
Web -->|Success| Parse{Element status OK?}
Parse -->|Yes| Convert["Convert meters to miles<br>(÷1609.34, round 1 decimal)"] --> Ret([Return result])
Parse -->|No, single pair| Err(["Set ErrorMessage,<br>do not throw"])
Parse -->|No, multi-address element| Zero(["Element contributes 0 miles"])
Failure and edge-case behavior¶
- Mismatched origin/destination counts in
GetMilesBetweenMultipleAddressesthrow before any HTTP request is sent. - Any network or parsing exception in
QueryGoogleApiis logged, then rethrown as a genericExceptionwith only the original message — the original exception type and stack trace are lost*. - A non-
"OK"status for a single-pair query (GetDataBetweenTwoAddresses) setsErrorMessagewithout throwing; the same condition for one element in a multi-address query yields 0 miles for that element rather than an error or a thrown exception. - Addresses are not URL-encoded before being placed in the query string, which risks malformed requests or parameter injection from address text containing reserved characters*.
- The Google API key is sent in the request query string, so it can appear in proxy or server access logs*.
Related documentation¶
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Sources¶
Services/SAIF.Services.Web.Proxies/GoogleMapsApiServiceProxy.cs