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);
        }
Example #2
0
        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);
        }