Reusing Addresses in Dynamics AX 2012: Part 1 – Address Standardization

by | Updated July 20, 2020 | Dynamics AX, Set Up, User Tips and Tricks

In my role as an Architect, I am often involved in integrating applications with Dynamics AX. On most projects we end up dealing with addresses. As you probably know, in Dynamics AX, an address is actually a global entity in the Global Address Book. Technically, it is stored in the LogisticsPostalAddress table.

Inevitably our client wants to avoid creating duplicate addresses and reuse the LogisticsPostalAddress record if possible. I can tell you that it is probably not worth the effort to do this if you simply want to save database space. However, I have come across some business requirements that require reusing addresses and justify the effort necessary to do that.

Address Standardization

The first step of reusing an address is to standardize the format so you can search for the existence of an address in the LogisticsPostalAddress field. The reason for standardization is so you are using a standardized string to search for a standardized string.

For example, if I want to look for the address for the Stoneridge Software Barnesville office, I would likely look on our website and see that our address is “101 Front St South Barnesville MN 56514.” I would then enter our address into the AX form and expect it to check for an existing address. However, if the address that was previously entered is “101 Front St S Barnesville MN 56514” then the system wouldn’t find a match using a string search

We could solve that problem by making our search much more intelligent but that is a pretty complicated algorithm. Why not just make sure that each address that is entered or searched is using the exact same format? That is where Address Standardization comes in.

One Possible Solution for Address Standardization in Dynamics AX

There are several services that will provide Address Standardization and even Validation (make sure the address actually exists). One solution is to write the code necessary to call one of those services to standardize addresses as they are entered. That is the purpose of this series of articles. I will show you a couple of ways to add code to standardize addresses in Dynamics AX as they are entered.

  • This first article will focus on creating a C# class and using it to make the call to the Address Standardization Service. We will simply use an AX Job to make the call and display some information in the Info Log window.
  • The second article will integrate that code into the user interface for a more complete solution.
  • The third article will attempt to implement the same solution using AX code without a C# assembly.
  • The fourth and final article will provide the same solution in the new Dynamics AX (previously known as AX 7).

The Standardization Service

There are several services that provide address standardization and validation. I will use one simply because it provides a robust solution and has a free subscription. The free subscription is limited to 250 addresses a month but that should be sufficient for our purposes. The solution I will be using is called Smarty Street (https://smartystreets.com). To follow along with this, you will need to sign-up for an account here (it’s free) and obtain an auth-id and auth-token.

I will take the following steps in this article:

  1. Create a C# Class Library project that will be used to make the calls to Smarty Streets. This step will include a test project to verify the code.
  2. I will deploy the solution to the Server and Client in AX.
  3. I will write an AX Job that will utilize the C# class library.

Create a C# Class Library project

There are many blog articles and walkthroughs on how to do this. I won’t go into the details for this. You can find more information on MSDN here. Here is a good set of blog articles that you may find helpful. Suffice it to say that we will create a C# Class Library.  Here are the initial steps that I took to get everything setup:

  1. Create a C# Class Library project named “SmartyStreetLib.”
  2. Rename the default class that is created to SmartyStreetAPI.
  3. Create a Unit Test project to test the SmartyStreeAPI class. You can use this walkthrough as an example.

Now that you have an empty class in a Class Library project you will need to add the code to the class. I have decided to add the following code:

  1. The properties used as inputs to call the Smarty Streets Address API
  2. A property to get hold the Status response from the Smarty Streets Address API call
  3. A property to hold the response headers from Smarty Streets Address API call
  4. A method to build the URL for the Smarty Streets Address API call
  5. A method to get the addresses returned from the call

Create properties for the SmartyStreeAPI class

Our first step is to create the properties necessary to make the API Call. Let’s look at what may be required. If we look at the documentation for the call (https://smartystreets.com/docs/us-street-api) we see two tables that are useful here. The first one shows the structure of the URL used to make the call and the second one shows the possible input parameters for the query portion of the call.

URL Composition

URL Components Values Notes
Scheme https NOTE: non-secure http requests are not supported
Hostname api.smartystreets.com
Path /street-address
Query String ?auth-id=123&auth-token=abc Authentication information, inputs, etc. Additional query string parameters are introduced in the next section.

 

Input Fields for Query String

Name Type Max Characters Default Value Description
input_id string 36 blank A unique identifier for this address used in your application; this field will be copied into the output.
street string 64 blank The street line of the address, or an entire address (which we call a “freeform” input)
street2 string 64 blank Any extra address information

(e.g., Leave it on the front porch.)

secondary string 32 blank Apartment, suite, or office number

(e.g., “Apt 52” or simply “52” ; not “Apt52”.)

city string 64 blank The city name
state string 32 blank The state name or abbreviation
zipcode string 16 blank The ZIP Code
lastline string 64 blank City, state, and ZIP Code combined
addressee string 64 blank The name of the recipient, firm, or company at this address
urbanization string 64 blank Only used with Puerto Rico
candidates integer Max Value: 10 1 The maximum number of valid addresses returned when the input is ambiguous

 

We will combine the Scheme, hostname, and path into a “base” URL. If I wanted to make my class more generic to support other APIs I would keep the different components for the base URL and construct it from those components. Since this will be specific to Smarty Streets, we will just combine the components into a single property.

Add the following code to the SmartyStreetAPI class:

We also notice that the query string will always include the auth-id and the auth-token. Let’s create two properties to contain those values. I like to standardize my properties to use camelcase and I also like to document my properties (and all members of a class) using the format that allows you to include HTML and other meaningful tags that can be used to generate class documentation. So we will add the following code to the SmartyStreetAPI class:

Now we will add a property for each input available for the query string. So here is the code I added in the SmartyStreetAPI class for the input parameter properties:

Our final set of properties will contain the status and response headers. The response headers are readily available from the WebClient class. We can see here that the WebClient class exposes the response headers using the WebHeaderCollection Class which extends the NameValueCollection Class. Enter the following code in the SmartyStreetAPI class to create a ResponseHeaders property for those headers:

Unfortunately, the WebClient class does not include the Status response as a response header. So we will need to create a special property to hold the status response. We will create a subclass in our SmartyStreetAPI class to represent a Status Response that will contain the response code and the description from the table below.

Status Code Response and Explanation
401 Unauthorized: The credentials were provided incorrectly or did not match any existing, active credentials.
402 Payment Required: There is no active subscription for the account associated with the credentials submitted with the request.
413 Request Entity Too Large: The maximum size for a request body to this API is 32K (32,768 bytes).
400 Bad Request (Malformed Payload): A GET request lacked a street field or the request body of a POST request contained malformed JSON.
200 OK (success!): A JSON array containing zero or more address matches for the input provided with the request. If none of the submitted addresses validate, the array will be empty ([]). The structure of the response is the same for both GET and POSTrequests.

 

Enter the following code in the SmartyStreetAPI class to define the Response Class:

Enter the following code in the SmartyStreetAPI class to provide a property for the Status Response:

Unfortunately the .NET WebClient class does not provide a means to get the status from your call. Of course we could simply assume the call was successful unless it throws an exception and we can get the status code from the WebException class but I wanted to expose the status in my SmartyStreetAPI class using the Status property. So I found this post on StackOverflow.com and it had a great solution for getting the status using reflection. Let’s add a static method to get the status response:

Create Public Methods for the SmartyStreetAPI class

We only have two methods left to create. We could do all the work in a single method that builds the URL query, makes the call and returns the addresses, however, it is much easier to test if we break that into two separate calls. One will create the URL query and the other will use it to get the addresses.

Creating the URL Query

Several of the input parameters are optional so we need to create the code that examines the parameters that are provided. Some parameters are required as a minimum so let’s also make sure those parameters are provided. Enter the following code into the SmartyStreetAPI class to build the URL Query:

Calling The Smarty Streets API

The final method we need to create is the call to the API to get one or more addresses. We are going to send a single address but we may bet one or more addresses in response, depending on the parameters we provide. So our method must return an array of addresses.

If we were not going to use this code in Dynamics AX I would use a List<Address> instead of an array. However, since X++ does not support making templated (generic) calls we need to use a standard non-generic type.

In the code we are going to do the following:

  1. instantiate a WebClient object
  2. Set the Request Headers
  3. Make the call (HTTP Post)
  4. Get the Response Headers
  5. Get the Status Response

The main question here is what headers are we going to use? If you look at the header options in the tables below you will see that there are two categories, Input/output options and query options. The input/output options specify what content type to use for input and output. Examples of content type or JSON and XML. The query options specify how to use the input values provided on the call.

Input/Output Header Options

Header Description Example
Content-Type The purpose of the Content-Type field is to describe the data contained in the body fully enough that the receiving user agent can pick an appropriate agent or mechanism to present the data to the user, or otherwise deal with the data in an appropriate manner. Content-Type: application/json
Accept The purpose of the Accept field is to describe the data that will be accepted in the response data. Content-Type: application/json

 

Query Header Options

Header Description Example
X-Standardize-Only Includes more than just verified results by standardizing addresses where the primary numbers fit into the range on the street.

 

Note: This header is not compatible with freeform addresses and is ignored for those inputs.

X-Standardize-Only: true
X-Include-Invalid Activates the most aggressive matching mode, which may include results for addresses that are not even remotely valid. As a side-effect, ambiguous addresses return only one candidate result, not multiple.

 

Note: This header is not compatible with freeform addresses and is ignored for those inputs.

X-Include-Invalid: true

 

We want to be able to get addresses standardized even if the address cannot be validated. Interestingly, the address for the Stoneridge Software Barnesville office does not validate. So we will use the X-Standardize-Only header to specify that we only want to standardize and not validate. You can use the Smarty Street Interactive page to see how this works.  Go to the page and enter “101 South Front St Barnesville MN 56514” as a freeform address.

Test Drive in Dynamics AX

You will get an error like this:

Addresses in Dynamics AX

Now go and enter it as components:

Test Drive Address Components

Now it tells you it is an invalid address but it still returns the address parsed. This is because the “X-Standardize-Only” header is set to “true.” However, when this header is set we cannot use the freeform address option. That means we need to at least send the “lastline” option or the “city”, “state” and “zipcode” separately.

Enter the following code into the SmartyStreetAPI class to make the API call:

Once you have this code it would seem we are done, but this project will not build. The reason is because the “Address” class has not been defined. We need to create a class that can hold the JSON output. Fortunately, Visual Studio has a simple way to do this. Simply copy the example output from the Smarty Streets API documentation page and paste it in the bottom of the SmartyStreetAPI.cs file using the Edit/Paste Special/Paste JSON as Classes. Since the output is an array and we only want to create the class, It is important to copy only the first instance of the class definition with its sub classes. Do not copy the JSON array symbol or the comma or the subsequent partial object definition. (see the image below).

Example output in Dynamics AX

Once you have that pasted into your SmartySTreetAPI.cs file you will need to rename the “RootObject” class to “Address”.

Address Code in Dynamics AX

Then you can simply reformat the file to have a readable, full definition of the Address class.

Address Class in Dynamics AX

Your project is missing one more thing to be able to build. The problem is this line in the DownloadSerializedJsonData method.

I chose to use the Json.Net library from Newtonsoft to deserialize the JSON return string into the Address class. This requires you to use the NuGet utility to get this library. Simply right click on the References node in your SmartyStreetLib project and click “Manage NuGet Packages …”. Use the “Search Online field find JSON.NET and add it to your project.

You will need the following “Using” statements in your SmartyStreetAPI class file to get everything to work. You may need to also add a reference to the System.Web library using the reference manager.

Now your class should successfully compile.

Testing the SmartyStreetAPI Class

Now that we have a class we can use, we should test it. You should already have a test project. In the interest of time and space I won’t provide a lot of details about creating a unit test. I will simply provide my unit test code below. You can run these two tests to verify your code.

Once these two tests pass, we are ready to call the class from inside AX.

Calling SmartyStreetAPI Class From AX

If you correctly added the Visual Studio project to the AOT you will be able to see it in the AOT in AX and will be able to use the SmartyStreetAPI. Remember, you will have to use the full namespace to reference it (ie. SmartyStreetLib.SmartyStreetAPI )

You will need to add the Newtonsoft library to the Server and Client deployments. I won’t go into details on the proper way to do that, but you can simply copy them for now. My Server directory is “C:\Program Files\Microsoft Dynamics AX\60\Server\DAXR3\bin\VSAssemblies”. Basically, you want to find the VSAssemblies directory in your Server\Bin directory. Copy the Newtonsoft.Json.dll file from [VS Projects Directory]\SmartyStreetLib\packages\Newtonsoft.Json.8.0.3\lib\net45. If you used a different .net library for your project make sure to match the correct directory for the newtonsoft library. You can find your .NET library in your Projects Properties under the Application tab.

Smarty Street Lib in Dynamics AX

You will need to also copy that file to the client folder. That is found in the [Users]\[Current User]\C:\Users\AppData\Local\Microsoft\Dynamics Ax\VSAssemblies{SomeGuid}. Since I was logged in as Administrator in a Contoso Demo environment, mine client path was in C:\Users\Administrator\AppData\Local\Microsoft\Dynamics Ax\VSAssemblies{25ADFFAF-205F-4317-91C3-533E3758794B}. There is a good series of articles explaining how to deploy this DLL properly here.

Add a new Job to the AOT (I like to create a private project and add it to that for future reference and for exporting purposes). Name it TestSmartyStreetLib and add the following code:

This should provide you with the following output:

Infolog in Dynamics AX

 

Stay tuned for my next post where we integrate this class into the UI for AX.

 

Related Posts

  • When we first set up Dynamics AX 2012 internally to run our business, we just added the bare bones address information to get by (Zip Codes, Cities, States and Counties),…

  • The Safari browser is now supported natively on Dynamics AX 2012 R2 as well as being supported on Dynamics AX RTM with a hotfix.  Taken from the updated System Requirements…

  • I put together some certification information on the requirements for Microsoft Dynamics AX 2012 and a proposed training roadmap to get to each of the core certifications.  Rather than have this…

1 Comment

  1. Michael Dave

    Great !! Thanks for the post.

Submit a Comment

Your email address will not be published. Required fields are marked *

Upcoming Events

november

05nov11:00 am12:00 pmConfab with Stoneridge - Livestream - Project Oakdale: The NEW Integration of Power Platform into Teams

18nov10:00 am10:30 amThe Modern Manufacturer - Tears and Trauma of MRP

19nov11:00 am12:00 pmConfab with Stoneridge - Livestream - Project Oaktree: NEW Functionality for Dynamics 365 Manufacturing

december

02dec9:00 am12:00 pmOnline Workshop - Dynamics GP Year End Close (Morning Session)

03dec11:00 am12:00 pmConfab with Stoneridge - Livestream: Live Agents, Power Virtual Agents, Omnichannel – Oh My!

03dec1:00 pm4:00 pmOnline Workshop - Dynamics GP Year End Close (Afternoon Session)

09dec10:00 am10:30 amThe Modern Manufacturer - Manufacturing Policy Management

17dec11:00 am12:00 pmConfab with Stoneridge - Livestream - Technology in 2020: A Year in Review

About Stoneridge
Stoneridge Software is a unique Microsoft Gold Partner, with emphasis on partner. With specialties in Microsoft Dynamics 365, Microsoft Dynamics AX, Microsoft Dynamics NAV, Microsoft Dynamics GP and Microsoft Dynamics CRM, we focus on attracting the most knowledgeable experts in the field to our team, and prioritize delivering stellar solutions with maximum impact for your business. At Stoneridge, we are deeply committed to your results. Each engagement is met with a dedicated team, ready to provide thorough, tailored, and expert service. Based in Minnesota, we intentionally “step into your shoes,” wherever you are. We focus on what you care about, and develop trusting, long-term relationships with our clients.

Subscribe To Our Blog

Sign up to get periodic updates on the latest posts.

Thank you for subscribing!

X