public bool Verify( Location location, bool reVerify )
{
bool success = false;
// Do not reverify any locked locations
if ( location == null || ( location.IsGeoPointLocked.HasValue && location.IsGeoPointLocked.Value ) )
{
return false;
}
string inputLocation = location.ToString();
// Create new context to save service log without affecting calling method's context
var rockContext = new RockContext();
Model.ServiceLogService logService = new Model.ServiceLogService( rockContext );
bool standardized = location.StandardizeAttemptedDateTime.HasValue && !reVerify;
bool geocoded = location.GeocodeAttemptedDateTime.HasValue && !reVerify;
bool anyActiveStandardizationService = false;
bool anyActiveGeocodingService = false;
// Save current values for situation when first service may successfully standardize or geocode, but not both
// In this scenario the first service's values should be preserved
string street1 = location.Street1;
string street2 = location.Street2;
string city = location.City;
string county = location.County;
string state = location.State;
string country = location.Country;
string postalCode = location.PostalCode;
string barcode = location.Barcode;
DbGeography geoPoint = location.GeoPoint;
// Try each of the verification services that were found through MEF
foreach ( var service in Rock.Address.VerificationContainer.Instance.Components )
{
var component = service.Value.Value;
if ( component != null &&
component.IsActive && (
( !standardized && component.SupportsStandardization ) ||
( !geocoded && component.SupportsGeocoding ) ) )
{
string resultMsg = string.Empty;
var result = component.Verify( location, out resultMsg );
if ( !standardized && component.SupportsStandardization )
{
anyActiveStandardizationService = true;
// Log the service and result
location.StandardizeAttemptedServiceType = service.Value.Metadata.ComponentName;
location.StandardizeAttemptedResult = resultMsg;
// As long as there wasn't a connection error, update the attempted datetime
if ( ( result & Address.VerificationResult.ConnectionError ) != Address.VerificationResult.ConnectionError )
{
location.StandardizeAttemptedDateTime = RockDateTime.Now;
}
// If location was successfully geocoded, update the timestamp
if ( ( result & Address.VerificationResult.Standardized ) == Address.VerificationResult.Standardized )
{
location.StandardizedDateTime = RockDateTime.Now;
standardized = true;
// Save standardized address in case another service is called for geocoding
street1 = location.Street1;
street2 = location.Street2;
city = location.City;
county = location.County;
state = location.State;
country = location.Country;
postalCode = location.PostalCode;
barcode = location.Barcode;
}
}
else
{
// Reset the address back to what it was originally or after previous service successfully standardized it
location.Street1 = street1;
location.Street2 = street2;
location.City = city;
location.County = county;
location.State = state;
location.Country = country;
location.PostalCode = postalCode;
location.Barcode = barcode;
}
if ( !geocoded && component.SupportsGeocoding )
{
anyActiveGeocodingService = true;
// Log the service and result
location.GeocodeAttemptedServiceType = service.Value.Metadata.ComponentName;
location.GeocodeAttemptedResult = resultMsg;
// As long as there wasn't a connection error, update the attempted datetime
if ( ( result & Address.VerificationResult.ConnectionError ) != Address.VerificationResult.ConnectionError )
{
location.GeocodeAttemptedDateTime = RockDateTime.Now;
}
// If location was successfully geocoded, update the timestamp
if ( ( result & Address.VerificationResult.Geocoded ) == Address.VerificationResult.Geocoded )
{
location.GeocodedDateTime = RockDateTime.Now;
geocoded = true;
// Save the lat/long in case another service is called for standardization
geoPoint = location.GeoPoint;
}
}
else
{
// Reset the lat/long back to what it was originally or after previous service successfully geocoded it
location.GeoPoint = geoPoint;
}
// Log the results of the service
if ( !string.IsNullOrWhiteSpace( resultMsg ) )
{
Model.ServiceLog log = new Model.ServiceLog();
log.LogDateTime = RockDateTime.Now;
log.Type = "Location Verify";
log.Name = service.Value.Metadata.ComponentName;
log.Input = inputLocation;
log.Result = resultMsg.Left( 200 );
log.Success = success;
logService.Add( log );
}
// If location has been succesfully standardized and geocoded, break to get out, otherwise next service will be attempted
if ( standardized && geocoded )
{
break;
}
}
}
// If there is only one type of active service (standardization/geocoding) the other type's attempted datetime
// needs to be updated so that the verification job will continue to process additional locations vs just getting
// stuck on the first batch and doing them over and over again because the other service type's attempted date is
// never updated.
if ( anyActiveStandardizationService && !anyActiveGeocodingService )
{
location.GeocodeAttemptedDateTime = RockDateTime.Now;
}
if ( anyActiveGeocodingService && !anyActiveStandardizationService )
{
location.StandardizeAttemptedDateTime = RockDateTime.Now;
}
rockContext.SaveChanges();
return standardized || geocoded;
}