Skip to content

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

  1. Construct GoogleMapsApiServiceProxy(ILogService, IEnvironmentService): guard both services (WP-BR-001), then read googlemaps.apibaseuri and googlemaps.apikey via GetConfigSetting (WP-BR-020).
  2. QueryGoogleApi(origins, destinations) (private): (WP-BR-021)
  3. Build the URL: {baseuri}distancematrix/xml?units=imperial&language=en&origins=a|b&destinations=c|d&key={apikey}; each address has %3Cbr%3E replaced by a space, and addresses are not URL-encoded.
  4. Send a WebRequest with a 5000 ms timeout, and load the response as an XDocument.
    • On failure: log via ILogService.LogException("GoogleMapsApiServiceProxy", "QueryGoogleApi", "WebRequest", e), then throw new Exception(e.Message) — the original exception type and stack trace are lost, and the response/stream are not disposed.
  5. GetDataBetweenTwoAddresses(o, d):
  6. Query the API (step 2).
  7. If the first element/status is "OK": set Miles from distance/value (meters ÷ 1609.34, rounded to 1 decimal — WP-BR-022), Distance from distance/text, Time from duration/text, and Seconds from duration/value.
    • If parsing fails: throw Exception("Google Maps API Service Error - unable to calculate mileage.").
  8. Otherwise: set ErrorMessage to the status message plus the status; nothing is thrown (WP-BR-023).
  9. GetMilesBetweenTwoAddresses(o, d): query the API, then convert the first distance/value to miles; any failure throws the generic mileage error.
  10. GetMilesFromManyToOneAddress(origins, destination) / GetMilesFromOneToManyAddresses(origin, destinations): query the API, then take each element's distance in miles.
  11. A failing element yields 0 and does not throw (WP-BR-024).
  12. GetMilesBetweenMultipleAddresses(origins, destinations):
  13. If the origin and destination counts differ: throw before any query is sent (WP-BR-025).
  14. Query the full matrix (step 2).
  15. For row i, take element i, pairing origin i with destination i (the diagonal).
  16. 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 GetMilesBetweenMultipleAddresses throw before any HTTP request is sent.
  • Any network or parsing exception in QueryGoogleApi is logged, then rethrown as a generic Exception with only the original message — the original exception type and stack trace are lost*.
  • A non-"OK" status for a single-pair query (GetDataBetweenTwoAddresses) sets ErrorMessage without 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*.

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