- C#
- Python
- NodeJS
Address GeoCode Canada C# Code Snippet
using AGCAService;
namespace address_geocode_canada_dot_net.SOAP
{
/// <summary>
/// Provides functionality to call the ServiceObjects Address Geocode CA (AGCA) SOAP service's GetGeoLocation operation,
/// retrieving geocoding information (e.g., latitude, longitude, postal code) for a given Canadian address with fallback to a backup endpoint
/// for reliability in live mode.
/// </summary>
public class GetGeoLocationValidation
{
private const string LiveBaseUrl = "https://sws.serviceobjects.com/GCC/soap.svc/SOAP";
private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/GCC/soap.svc/SOAP";
private const string TrialBaseUrl = "https://trial.serviceobjects.com/GCC/soap.svc/SOAP";
private readonly string _primaryUrl;
private readonly string _backupUrl;
private readonly int _timeoutMs;
private readonly bool _isLive;
/// <summary>
/// Initializes URLs/timeout/IsLive.
/// </summary>
public GetGeoLocationValidation(bool isLive)
{
_timeoutMs = 10000;
_isLive = isLive;
_primaryUrl = isLive ? LiveBaseUrl : TrialBaseUrl;
_backupUrl = isLive ? BackupBaseUrl : TrialBaseUrl;
if (string.IsNullOrWhiteSpace(_primaryUrl))
throw new InvalidOperationException("Primary URL not set.");
if (string.IsNullOrWhiteSpace(_backupUrl))
throw new InvalidOperationException("Backup URL not set.");
}
/// <summary>
/// Async, returns the latitude and longitude for a given Canadian address. This operation will use cascading logic when an exact address match is not found and it will return the next closest level match available. The operation output is designed to allow the service to return new pieces of data as they become available without having to re-integrate.
/// </summary>
/// <param name="Address">Address line of the address to geocode. For example, “124 Main Street”. Required.</param>
/// <param name="Municipality">The municipality of the address to geocode. For example, “Cayuga”. Optional if postal code is provided.</param>
/// <param name="Province">The province of the address to geocode. For example, “ON”. Optional if postal code is provided.</param>
/// <param name="PostalCode">The postal code of the address to geocode. Optional if municipality and province are provided.</param>
/// <param name="LicenseKey">Your license key to use the service.</param>
public async Task<Location> GetGeoLocation(string Address, string Municipality, string Province, string PostalCode, string LicenseKey)
{
GCCSoapServiceClient clientPrimary = null;
GCCSoapServiceClient clientBackup = null;
try
{
// Attempt Primary
clientPrimary = new GCCSoapServiceClient();
clientPrimary.Endpoint.Address = new System.ServiceModel.EndpointAddress(_primaryUrl);
clientPrimary.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
Location response = await clientPrimary.GetGeoLocationAsync(
Address, Municipality, Province, PostalCode, LicenseKey).ConfigureAwait(false);
if (_isLive && !IsValid(response))
{
throw new InvalidOperationException("Primary endpoint returned null or a fatal Number=4 error for GetGeoLocation");
}
return response;
}
catch (Exception primaryEx)
{
try
{
clientBackup = new GCCSoapServiceClient();
clientBackup.Endpoint.Address = new System.ServiceModel.EndpointAddress(_backupUrl);
clientBackup.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(_timeoutMs);
return await clientBackup.GetGeoLocationAsync(
Address, Municipality, Province, PostalCode, LicenseKey).ConfigureAwait(false);
}
catch (Exception backupEx)
{
throw new InvalidOperationException(
$"Both primary and backup endpoints failed.\n" +
$"Primary error: {primaryEx.Message}\n" +
$"Backup error: {backupEx.Message}");
}
finally
{
clientBackup?.Close();
}
}
finally
{
clientPrimary?.Close();
}
}
private static bool IsValid(Location response) => response?.Error == null || response.Error.Number != "4";
}
}
Address GeoCode Canada Python Code Snippet
from suds.client import Client
from suds import WebFault
from suds.sudsobject import Object
class GetGeoLocationSoap:
def __init__(self, license_key: str, is_live: bool = True, timeout_ms: int = 15000):
"""
license_key: Service Objects AGCA license key.
is_live: Whether to use live or trial endpoints
timeout_ms: SOAP call timeout in milliseconds
"""
self.is_live = is_live
self.timeout = timeout_ms / 1000.0
self.license_key = license_key
# WSDL URLs
self._primary_wsdl = (
"https://sws.serviceobjects.com/GCC/soap.svc?wsdl"
if is_live
else "https://trial.serviceobjects.com/GCC/soap.svc?wsdl"
)
self._backup_wsdl = (
"https://swsbackup.serviceobjects.com/GCC/soap.svc?wsdl"
if is_live
else "https://trial.serviceobjects.com/GCC/soap.svc?wsdl"
)
def get_geo_location(
self, address: str, municipality: str, province: str, postal_code: str
) -> Object:
"""
Calls the GetGeoLocation SOAP API to retrieve the information.
Parameters:
address: Address line of the address to geocode (e.g., "123 Main Street").
municipality: The municipality of the address to geocode (e.g., "Cayuga").
province: The province of the address to geocode (e.g., "ON").
postal_code: The postal code of the address to geocode (e.g., "N0A 1E0").
license_key: Your ServiceObjects license key.
is_live: Determines whether to use the live or trial servers.
timeout_ms: Timeout, in milliseconds, for the call to the service.
Returns:
suds.sudsobject.Object: SOAP response containing geocoding details or error.
"""
# Common kwargs for both calls
call_kwargs = dict(
Address=address,
Municipality=municipality,
Province=province,
PostalCode=postal_code,
LicenseKey=self.license_key,
)
# Attempt primary
try:
client = Client(self._primary_wsdl)
# Override endpoint URL if needed:
# client.set_options(location=self._primary_wsdl.replace('?wsdl','/soap'))
response = client.service.GetGeoLocation(**call_kwargs)
# If response invalid or Error.Number == "4", trigger fallback
if response is None or (
hasattr(response, "Error")
and response.Error
and response.Error.Number == "4"
):
raise ValueError("Primary returned no result or Error.Number=4")
return response
except (WebFault, ValueError, Exception) as primary_ex:
try:
client = Client(self._backup_wsdl)
response = client.service.GetGeoLocation(**call_kwargs)
if response is None:
raise ValueError("Backup returned no result")
return response
except (WebFault, Exception) as backup_ex:
msg = (
"Both primary and backup endpoints failed.\n"
f"Primary error: {str(primary_ex)}\n"
f"Backup error: {str(backup_ex)}"
)
raise RuntimeError(msg)
Address GeoCode Canada NodeJS Code Snippet
import { soap } from 'strong-soap';
/**
* <summary>
* A class that provides functionality to call the ServiceObjects Address Geocode CA (AGCA) SOAP service's GetGeoLocation endpoint,
* retrieving geocoding information (e.g., latitude, longitude, postal code) for a given Canadian address with fallback to a backup endpoint for reliability in live mode.
* </summary>
*/
class GetGeoLocationSoap {
/**
* <summary>
* Initializes a new instance of the GetGeoLocationSoap class with the provided input parameters,
* setting up primary and backup WSDL URLs based on the live/trial mode.
* </summary>
* @param {string} Address - Address line of the address to geocode (e.g., "123 Main Street").
* @param {string} Municipality - The municipality of the address to geocode (e.g., "Cayuga").
* @param {string} Province - The province of the address to geocode (e.g., "ON").
* @param {string} PostalCode - The postal code of the address to geocode (e.g., "K1A 0A1").
* @param {string} LicenseKey - Your license key to use the service.
* @param {boolean} isLive - Value to determine whether to use the live or trial servers.
*/
constructor(Address, Municipality, Province, PostalCode, LicenseKey, isLive = true, timeoutSeconds = 15) {
this.args = {
Address,
Municipality,
Province,
PostalCode,
LicenseKey
};
this.isLive = isLive;
this.timeoutSeconds = timeoutSeconds;
this.LiveBaseUrl = "https://sws.serviceobjects.com/GCC/soap.svc?wsdl";
this.BackupBaseUrl = "https://swsbackup.serviceobjects.com/GCC/soap.svc?wsdl";
this.TrialBaseUrl = "https://trial.serviceobjects.com/GCC/soap.svc?wsdl";
this._primaryWsdl = this.isLive ? this.LiveBaseUrl : this.TrialBaseUrl;
this._backupWsdl = this.isLive ? this.BackupBaseUrl : this.TrialBaseUrl;
}
/**
* <summary>
* Asynchronously calls the GetGeoLocation SOAP endpoint, attempting the primary endpoint
* first and falling back to the backup if the response is invalid (Error.Number == '4') in live mode
* or if the primary call fails.
* </summary>
* <returns type="Promise<GetGeoLocationResponse>">A promise that resolves to a GetGeoLocationResponse object containing geocoding details or an error.</returns>
* <exception cref="Error">Thrown if both primary and backup calls fail, with detailed error messages.</exception>
*/
async invokeAsync() {
try {
const primaryResult = await this._callSoap(this._primaryWsdl, this.args);
if (this.isLive && !this._isValid(primaryResult)) {
console.warn("Primary returned Error.Number == '4', falling back to backup...");
const backupResult = await this._callSoap(this._backupWsdl, this.args);
return backupResult;
}
return primaryResult;
} catch (primaryErr) {
try {
const backupResult = await this._callSoap(this._backupWsdl, this.args);
return backupResult;
} catch (backupErr) {
throw new Error(`Both primary and backup calls failed:\nPrimary: ${primaryErr.message}\nBackup: ${backupErr.message}`);
}
}
}
/**
* <summary>
* Performs a SOAP service call to the specified WSDL URL with the given arguments,
* creating a client and processing the response into a GetGeoLocationResponse object.
* </summary>
* <param name="wsdlUrl" type="string">The WSDL URL of the SOAP service endpoint (primary or backup).</param>
* <param name="args" type="Object">The arguments to pass to the GetGeoLocation method.</param>
* <returns type="Promise<GetGeoLocationResponse>">A promise that resolves to a GetGeoLocationResponse object containing the SOAP response data.</returns>
* <exception cref="Error">Thrown if the SOAP client creation fails, the service call fails, or the response cannot be parsed.</exception>
*/
_callSoap(wsdlUrl, args) {
return new Promise((resolve, reject) => {
soap.createClient(wsdlUrl, { timeout: this.timeoutSeconds * 1000 }, (err, client) => {
if (err) return reject(err);
client.GetGeoLocation(args, (err, result) => {
const rawData = result?.Location;
try {
if (!rawData) {
return reject(new Error("SOAP response is empty or undefined."));
}
resolve(rawData);
} catch (parseErr) {
reject(new Error(`Failed to parse SOAP response: ${parseErr.message}`));
}
});
});
});
}
/**
* <summary>
* Checks if a SOAP response is valid by verifying that it exists and either has no Error object
* or the Error.Number is not equal to '4'.
* </summary>
* <param name="response" type="GetGeoLocationResponse">The GetGeoLocationResponse object to validate.</param>
* <returns type="boolean">True if the response is valid, false otherwise.</returns>
*/
_isValid(response) {
return response && (!response.Error || response.Error.Number !== '4');
}
}
export { GetGeoLocationSoap };