AX 7. URLUtility extension to create deep links.

In AX 7 we can use URL to open any form and it’s quite handy. Out of the box there is a feature called “Get link” that helps us to generate and share links. We can find it under Options -> Share -> Get Link.

GetLink.png

However, it has a limitation – you cannot generate link to open a specific record (so called “deep links”).

We can generate deep links from code by using URLGenerator class (there is a wiki article with explanations ), but it requires quite a bit of code to write. So I did small extension to URLUtility class to simplify this process.

It adds two new methods: generateRecordUrlFromDataSource and generateRecordUrl.

  • generateRecordUrlFromDataSource accepts form data source and generates a link to the record based on current record primary index fields.
  • generateRecordUrl accepts all parameters that are required to open a form, like menu item name and type, form data source name and map with key field’s IDs and values.
using Microsoft.Dynamics.AX.Framework.Utilities;
using Microsoft.Dynamics.@Client.ServerForm.Contexts;

/// <summary>
/// The class <c>URLUtility_Extension</c> contains extension methods for the <c>URLUtility</c> class.
/// </summary>
[ExtensionOf(classStr(URLUtility))]
public static class URLUtility_Extension
{
    public static str generateRecordUrl(str _menuItemName, MenuItemType _menuItemType, DataSourceName _dataSourceName, Map _indexFieldValuesMap, DataAreaId _dataAreaId = curExt())
    {
        System.Uri host                     = SessionContext::Get_Current().Get_RequestUrl();
        UrlHelper.UrlGenerator generator    = new UrlHelper.UrlGenerator();
        generator.MenuItemName              = _menuItemName;
        generator.MenuItemType              = _menuItemType;
        generator.HostUrl                   = host.GetLeftPart(System.UriPartial::Path);
        generator.Company                   = _dataAreaId;
        generator.EncryptRequestQuery       = true;

        if (_dataSourceName && _indexFieldValuesMap)
        {
            MapEnumerator mapEnumerator = _indexFieldValuesMap.getEnumerator();

            var requestQueryParameterCollection = generator.RequestQueryParameterCollection;

            while (mapEnumerator.moveNext())
            {
                requestQueryParameterCollection.UpdateOrAddEntry(_dataSourceName, mapEnumerator.currentKey(), mapEnumerator.currentValue());
            }
        }

        return generator.GenerateFullUrl().AbsoluteUri;
    }

    public static str generateRecordUrlFromDataSource(FormDataSource _formDataSource)
    {
        FormRun         formRun         = _formDataSource.formRun();
        str             menuItemName    = formRun.args().menuItemName();
        MenuItemType    menuItemType    = formRun.args().menuItemType();
        DataSourceName  dataSourceName  = _formDataSource.name();

        TableId   tableId   = _formDataSource.table();
        DictTable dictTable = new DictTable(tableId);
        DictIndex dictIndex = new DictIndex(tableId, dictTable.primaryIndex());

        int     fieldCount          = dictIndex.numberOfFields();
        Map     indexFieldValuesMap = new Map(Types::String, Types::String);
        Common  record              = _formDataSource.cursor();
        FieldId primaryKeyFieldId;

        for (int fieldIndex = 1; fieldIndex <= fieldCount; fieldIndex++)
        {
            primaryKeyFieldId = dictIndex.field(fieldIndex);

            indexFieldValuesMap.insert(fieldId2Name(tableId, primaryKeyFieldId), any2Str(record.(primaryKeyFieldId)));
        }

        return URLUtility::generateRecordUrl(menuItemName, menuItemType, dataSourceName, indexFieldValuesMap, record.DataAreaId);
    }
}

To test this class, you can use simple job:

class RunnableClass1
{
    public static void main(Args _args)
    {
        Map indexFieldValuesMap = new Map(Types::String, Types::String);
        indexFieldValuesMap.insert(fieldStr(VendTable, AccountNum), '1002');

        Box::info(URLUtility::generateRecordUrl(menuItemDisplayStr(VendTable), MenuItemType::Display, identifierStr(VendTable), indexFieldValuesMap, 'usmf'));
    }
}

It’s an initial version, so feel free to post comments in case of any bugs!

Advertisements

4 thoughts on “AX 7. URLUtility extension to create deep links.

  1. Joel January 5, 2017 / 9:29 pm

    Great post.

    Have you thought about a concept where AX could accept URL parameters from another system? For example, if someone is in CRM can they click on a link that opens Vendor 1002 without having that link generated from AX?

    • ievgensaxblog January 6, 2017 / 12:47 am

      Hi Joel,
      I actually don’t see any reason why you cannot use same code outside of AX. URL is generated using Microsoft.Dynamics.AX.Framework.Utilities dll. Create new console application, add reference to dll and write next code:


      using Microsoft.Dynamics.AX.Framework.Utilities.UrlHelper;
      using System;

      namespace URLGeneratorTest
      {
      class Program
      {
      static void Main(string[] args)
      {
      UrlGenerator generator = new UrlGenerator();
      generator.MenuItemName = "VendTable";
      generator.MenuItemType = UrlGenerator.MenuItemTypes.Display;
      generator.HostUrl = @"https://yourvmname.cloudax.dynamics.com/";
      generator.Company = "usmf";

      var requestQueryParameterCollection = generator.RequestQueryParameterCollection;

      requestQueryParameterCollection.UpdateOrAddEntry("VendTable", "AccountNum", "1002");

      Console.WriteLine(generator.GenerateFullUrl().AbsoluteUri);
      }
      }
      }

      All you need to know is menu item name and data source name.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s