public bool ValidateAddress() { bool result = true; // create request payload var zipLookup = new CityStateLookupRequest { USERID = "", ZipCode = new CityStateLookupRequestZipCode { ID = 0, Zip5 = this.Customer.BillingProfile.Address.PostalCode } }; // build query XmlSerializer serializerRequest = new XmlSerializer(typeof(CityStateLookupRequest)); var writer = new StringWriter(); serializerRequest.Serialize(writer, zipLookup); var query = string.Format("http://production.shippingapis.com/ShippingAPI.dll?API=CityStateLookup&XML={0}", writer.ToString()); // submit request CityStateLookupResponse uspsResponse; var httpRequest = WebRequest.Create(query); using (var reader = new StreamReader(httpRequest.GetResponse().GetResponseStream())) { XmlSerializer serializerResponse = new XmlSerializer(typeof(CityStateLookupResponse)); uspsResponse = (CityStateLookupResponse)serializerResponse.Deserialize(new StringReader(reader.ReadToEnd())); } // check if city & state match zip if (this.Customer.BillingProfile.Address.City != uspsResponse.ZipCode.City) { ValidationErrors.Add("City provided is not valid for the specified postal code " + Customer.BillingProfile.Address.PostalCode); result = false; } if (this.Customer.BillingProfile.Address.State != uspsResponse.ZipCode.State) { ValidationErrors.Add("State provided is not valid for the specified postal code " + Customer.BillingProfile.Address.PostalCode); result = false; } return(result); }
internal static async Task <List <ZipCode> > CityStateLookupAsync(List <ZipCode> input) { // limit is 5 addresses per request string requestGuid = Guid.NewGuid().ToString(); Log.Information("{area}: New request for {packageTotal} packages. {requestGuid}", "CityStateLookup()", input.Count, requestGuid); List <ZipCode> output = new(); CityStateLookupRequest request; int index = 0; while (index < input.Count) { request = new CityStateLookupRequest { ZipCode = input.Skip(index).Take(5).ToList(), USERID = UspsApiUsername, }; Log.Information("{area}: Fetching rates for {packageCount} package(s). {requestGuid}", "CityStateLookup()", input.Count, requestGuid); XmlSerializer xsSubmit = new(typeof(CityStateLookupRequest)); var xml = ""; using (var sww = new StringWriter()) { using XmlWriter writer = XmlWriter.Create(sww); xsSubmit.Serialize(writer, request); xml = sww.ToString(); } string uspsUrl = "https://secure.shippingapis.com/ShippingAPI.dll"; var formData = new FormUrlEncodedContent(new[] { new KeyValuePair <string, string>("API", "CityStateLookup"), new KeyValuePair <string, string>("XML", xml) }); HttpClient httpClient = new() { Timeout = TimeSpan.FromSeconds(120) }; HttpResponseMessage response = null; int retryCount = 0; DateTime responseTimer = DateTime.Now; retry: while (response == null || response.StatusCode != System.Net.HttpStatusCode.OK) { if (retryCount > 50) { Log.Error("{area}: USPS Failed to Respond after 50 attempts. {requestGuid}", "CityStateLookup()", retryCount, requestGuid); throw new UspsApiException("408: After many attempts, the request to the USPS API did not recieve a response. Please try again later."); } if (retryCount > 0) { Log.Warning("{area}: USPS Failed to Respond after " + retryCount + " seconds. Attempt {retryCount}. {requestGuid}", "CityStateLookup()", retryCount, requestGuid); } try { response = await httpClient.PostAsync(uspsUrl, formData).ConfigureAwait(false); Thread.Sleep(2500 * retryCount); httpClient.CancelPendingRequests(); retryCount++; } catch { httpClient.CancelPendingRequests(); retryCount++; goto retry; } } TimeSpan responseTime = DateTime.Now.TimeOfDay.Subtract(responseTimer.TimeOfDay); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); Log.Information("{area}: USPS response received in {responseTime} ms. {requestGuid}", "CityStateLookup()", responseTime.Milliseconds, requestGuid); try { XmlSerializer deserializer = new(typeof(CityStateLookupResponse)); var ms = new MemoryStream(Encoding.UTF8.GetBytes(content)); CityStateLookupResponse responseJson = (CityStateLookupResponse)deserializer.Deserialize(ms); index += 5; foreach (ZipCode zip in responseJson.ZipCode) { if (zip.Error != null) { Log.Warning("{area}: USPS Returned Error: {uspsErrorNumber} {uspsErrorDescription} {requestGuid}", "CityStateLookup()", zip.Error.Number, zip.Error.Description, requestGuid); output.Add(zip); } else { // preserve ID ZipCode orig = input.First(i => i.Zip5 == zip.Zip5); orig.City = zip.City; orig.State = zip.State; output.Add(orig); } } } catch (Exception ex) { Log.Error("{area}: Exception: {ex} {requestGuid}", "CityStateLookup()", ex.ToString(), requestGuid); throw new UspsApiException(ex); } } if (output.Count != input.Count) { // something went wrong because counts should always match Console.WriteLine("Counts did not match between input and output"); Log.Error("{area}: Counts did not match between input and output. {requestGuid}", "CityStateLookup()", requestGuid); throw new UspsApiException("Counts did not match between input and output"); } return(output); }