Introduction
This post covers the steps needed to use the Street Address Validation Application Programming Interface (API) of United Parcel Service (UPS). We will cover the steps of registering with UPS first to get credentials/license key from UPS and then use the street address validation API in a C# console application. We will use Visual Studio 2015 as Integrated Development Environment (IDE) and build a Windows Communication Foundation (WCF) client to invoke the UPS API.
Assumptions:
- You are familiar with a .net programming language (preferably C#) and Visual Studio .Net.
- You understand the basics of Windows Communication Foundation and how to consume a web service with the help of a WSDL file.
If you perform an internet search on the keywords ‘UPS Developer API’, you will get the link to the web page that covers all the documentation you need. The link is:
https://www.ups.com/upsdeveloperkit
In order to access UPS API, you need a userid/password credential and an access key.
Step 1: Get Security Credentials
Get a userid and password by registering with My UPS if you don’t have one already. This is step 1 on UPS web page.
Step 2: Get Access Key
Login to the same page mentioned above by using the credentials obtained in step 1 and request access key (Step 5 on the page). The access key will be displayed on your browser window. You will also get an email with the same access key information.
Now we are ready to write code.
Step 3: Build Code
Step 3a: Download API Files
UPS exposes different APIs for different types of functionality. In this tutorial, we will use their ‘Address Validation – Street Level’ API. Please go ahead and download the API documentation.
The API will be downloaded as a zip file. Extract the zip file to a folder of your choice. Navigate to the folder that contains the WSDLs of the Address Validation Service. If you extracted the zip file to a folder called ‘C:\UPS’, you will have to navigate to ‘C:\UPS\Street Level Address Validation for SHIPPING\XAVWebServices\SCHEMAS-WSDLs’
Please note that the WSDL file and all its dependencies (XML schemas) exist in the same folder.
Step 3b: Create Console Project
Step 3c: Add Service Reference
Right click on the console project and add service reference to the UPS service.
Now provide the full path of the WSDL file. Rename the proxy namespace to XAVServiceProxy.
Also, please note how Visual Studio adds WCF client configuration to your app.config file. You don’t need to change this please note the address of the service and the types of binding and contract. The service endpoint URL is the URL of UPS test environment.
Step3d: Add code
Add the following code to the Program.cs project startup class. I have tried to document the code as much as possible so it becomes self-explanatory.
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using UPSStreetAddressValidationConsoleApplication.XAVServiceProxy; namespace UPSStreetAddressValidationConsoleApplication { class Program { static void Main(string[] args) { try { //this is the remote proxy object XAVPortTypeClient Proxy = new XAVPortTypeClient(); //build the username token object UPSSecurityUsernameToken UPSSecurityUsernameTokenObj = new UPSSecurityUsernameToken(); //use your userid when youn registered with my UPS UPSSecurityUsernameTokenObj.Username = "your user id"; //use the password associated with your userid UPSSecurityUsernameTokenObj.Password = "your password"; //build the security access token object UPSSecurityServiceAccessToken UPSSecurityServiceAccessTokenObj = new UPSSecurityServiceAccessToken(); //your access key provided by UPS UPSSecurityServiceAccessTokenObj.AccessLicenseNumber = "your access key"; //set the username and service access objects on the UPSSecurity input parm object //this is the first parameter of the ProcessXAV method on UPS service UPSSecurity UPSSecurityObj = new UPSSecurity(); UPSSecurityObj.UsernameToken = UPSSecurityUsernameTokenObj; UPSSecurityObj.ServiceAccessToken = UPSSecurityServiceAccessTokenObj; //build the transaction reference type TransactionReferenceType TransactionReferenceTypeObj = new TransactionReferenceType(); //pass any value TransactionReferenceTypeObj.CustomerContext = "Customer Data"; //pass any value TransactionReferenceTypeObj.TransactionIdentifier = "12335"; //build the request type RequestType RequestTypeObj = new RequestType(); //this value has to be 1 RequestTypeObj.RequestOption = new String[1] { "1"}; RequestTypeObj.TransactionReference = TransactionReferenceTypeObj; //this is the class where we will pass the address data elements //passing address of new York stock exchange for testing purpose AddressKeyFormatType AddressKeyFormatTypeObj = new AddressKeyFormatType(); AddressKeyFormatTypeObj.AddressLine = new String[1] { "11 Wall Street" }; //political division 1 is required for get valid address validation code //otherwise you get an exception AddressKeyFormatTypeObj.PoliticalDivision1 = "NY"; //state code AddressKeyFormatTypeObj.PoliticalDivision2 = "New York"; //city AddressKeyFormatTypeObj.CountryCode = "US"; //country must be US or PR AddressKeyFormatTypeObj.PostcodePrimaryLow = ""; //passing a blank value //now let’s build the second parameter XAVRequest XAVRequestObj = new XAVRequest(); XAVRequestObj.AddressKeyFormat = AddressKeyFormatTypeObj; XAVRequestObj.Request = RequestTypeObj; //added to handle the intermittent error with SSL/TLS connection ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; //open channel Proxy.Open(); //call the service XAVResponse Response = Proxy.ProcessXAV(UPSSecurityObj, XAVRequestObj); //parse the result ItemChoiceType Result = Response.ItemElementName; //found multiple matches if (Result == ItemChoiceType.AmbiguousAddressIndicator) { Console.WriteLine(String.Format("Ambiguous Address.Found {0} matching candidate addresses", Response.Candidate.Length.ToString())); //print each candidate address that was returned as response foreach (CandidateType candidateAddress in Response.Candidate) { Console.WriteLine(String.Format("Consignee Name: {0}", candidateAddress.AddressKeyFormat.ConsigneeName)); Console.WriteLine(String.Format("Street Line 1: {0}", candidateAddress.AddressKeyFormat.AddressLine[0])); if (candidateAddress.AddressKeyFormat.AddressLine.Length > 1) Console.WriteLine(String.Format("Street Line 2: {0}", candidateAddress.AddressKeyFormat.AddressLine[1])); Console.WriteLine(String.Format("City: {0}", candidateAddress.AddressKeyFormat.PoliticalDivision2)); Console.WriteLine(String.Format("State: {0}", candidateAddress.AddressKeyFormat.PoliticalDivision1)); Console.WriteLine(String.Format("Zip: {0}-{1}", candidateAddress.AddressKeyFormat.PostcodePrimaryLow, Response.Candidate[0].AddressKeyFormat.PostcodeExtendedLow)); } } //invalid address no match found else if (Result == ItemChoiceType.NoCandidatesIndicator) Console.WriteLine("Invalid Address"); //valid address exactly one candidate returned else if (Result == ItemChoiceType.ValidAddressIndicator) { Console.WriteLine("Valid Address"); Console.WriteLine(String.Format("Consignee Name: {0}", Response.Candidate[0].AddressKeyFormat.ConsigneeName)); Console.WriteLine(String.Format("Street Line 1: {0}", Response.Candidate[0].AddressKeyFormat.AddressLine[0])); if (Response.Candidate[0].AddressKeyFormat.AddressLine.Length > 1) Console.WriteLine(String.Format("Street Line 2: {0}", Response.Candidate[0].AddressKeyFormat.AddressLine[1])); Console.WriteLine(String.Format("City: {0}", Response.Candidate[0].AddressKeyFormat.PoliticalDivision2)); Console.WriteLine(String.Format("State: {0}", Response.Candidate[0].AddressKeyFormat.PoliticalDivision1)); Console.WriteLine(String.Format("Zip: {0}-{1}", Response.Candidate[0].AddressKeyFormat.PostcodePrimaryLow, Response.Candidate[0].AddressKeyFormat.PostcodeExtendedLow)); } //close communication channel Proxy.Close(); } catch (Exception ex) { //please add code to handle SOAP exceptions Console.WriteLine(ex.Message); } //do not close the console window unless the user presses a key Console.ReadKey(); } } } |
Step 4: Test the code
Run the project and test with different values of address input. I have used the address of the New York Stock Exchange as a test address in my code example.
Please note:
- As per their website, the UPS Test URL works only for California and New York State addresses.
- Make sure you pass ‘US’ or ‘PR’ as country code. If you do not pass one of two values, you will get a SOAP Exception. The current UPS API supports US and Puerto Rico country codes.
- Make sure you pass value of “1” as RequestOption. Please see code comments for more details.
- Pass the two character state code in Political Division 1. If you don’t, you will get an exception.
- Pass the city name in the PoliticalDivision2 field.
- I found UPS documentation to be dated and out of synch with their current code. But it is still a good idea to read their documentation to get some general ideas about their service.
- The code in this post works at the time of writing this post (December 1, 2016).
- No warranty is provided with the code or any documentation in this article.
This code could be refactored into multiple helper methods but I wanted to provide one block of code with no dependencies to keep things simple for this post.
I will continue to test their APIs and try RESTful invocation if their API supports it. If you have any questions, feel free to post those in the comments area. Your feedback, as always, is appreciated.