Microsoft Portal – Retrieve Dynamics 365 Data Asynchronously – Part 2

In part 1 of this post I demonstrated building and using a service which receives a FetchXML query and returns Dynamics 365 data to any Portal page in an asynchronous manner as a JSON object. This service is similar to the SDK’s RetrieveMultiple message.
In this part 2, I’ll demonstrate a different service, which like the SDK Retrieve message, receives a record type, record id (GUID) and columns set to return the required data as a JSON object.
This is useful when you already have a specific Dynamics 365 record id at hand and you want to retrieve additional data for this record.

  1. Create a Web Template  named RetrieveService

    Set the Mime Type is to application/json.
    create web template

    Paste the following code in to the web template source and save.

    {% comment %} test for required parameters {% endcomment %}
    {% if request.params[‘entityname’] and request.params[‘id’] and request.params[‘columnset’] %}

    {% capture msg_no_data %}No data for specified attribute {% endcapture %}

    {% comment %} extract parameters {% endcomment %}
    {% comment %} extract target entity {% endcomment %}
    {% assign entityname = request.params[‘entityname’] %}
    {% comment %} extract target record id {% endcomment %}
    {% assign id = request.params[‘id’] %}
    {% comment %} parse requested attributes into array {% endcomment %}
    {% assign columnset = request.params[‘columnset’] | split: “,” %}

    {% comment %} query for target entity  {% endcomment %}
    {% assign item = entities[request.params[‘entityname’]][request.params[‘id’]] %} 

    {% comment %} Emit JSON response {% endcomment %}
        {% if item %}{
            {% comment %} Iterate throguh requestd attributes array {% endcomment %}
            {% for att in columnset %}
                {% comment %} Handle optionset attribute {% endcomment %}
                {% if item[att].label %}”{{ att }}”:”{{ item[att].label | default: msg_no_data }}”
                {% comment %} Handle lookup attribute {% endcomment %}
                {% elseif item[att].name %}”{{ att }}”:{“name”:”{{ item[att].name | default: msg_no_data }}”,”id”:”{{ item[att].id | default: msg_no_data }}”}                           
                {% comment %} Handle other attributes {% endcomment %}
                {% else %}”{{ att }}”:”{{ item[att] | default: msg_no_data }}”
                {% endif %}{% unless forloop.last %},{% endunless %}
            {% endfor -%}                   
        }   
        {% endif %}

    {% comment %} handle missing parameters {% endcomment %}
    {% else %}
      { “error”:”Missing one or more required parameter(s): entityname, id, columnset” }
    {% endif %}

  2. Create a Page Template named RetrieveService
    Map the Page Template to the Web Template created on step 1 above.
    Uncheck the Header and Footer checkbox.

    image

  3. Create a Portal Page named RetrieveService
    Set Home as parent page.
    Map the page to the Page Template created on step 2 and copy the partial URL which is used in the next step

    create a portal page

  4. Consume Service

    Use the following code sample anywhere you need asynchronous data retrieval of from Dynamics 365. In my example it is located in the Home page JavaScript portion.
    Note the URL address which maps to the Page (created above) URL.
    Replace the entityname, id and columnset parameters.
    Most important: make sure your users have the required Entity Permissions for the entities queried, otherwise they will receive empty results.

    $(function (){
      //define asynchronous request from any portal page
        $.ajax({
            method: “POST”,       
            url: “/retrieveservice/”,
            data: {
                //define entity name, id and columnset 
              entityname: ‘incident‘,
              id: ‘D2A697CD-D3C7-E811-A965-000D3AB0F1D7‘,
              columnset: ‘ticketnumber,title,createdon,incidentid,statecode,caseorigincode,customerid,ownerid‘  
            }
        }).done(function (msg){
            console.log(msg);
        }).fail(function (jqXHR, textStatus, errorThrown){
            console.log(textStatus);
        });
    });

    As the sample code logs the resulting JSON object to the console, open the browser developers tool (F12) to view it.

    Resulting JSON object

Advertisement

Microsoft Portal – Retrieve Dynamics 365 Data Asynchronously – Part 1

Leveraging Colin Vermander brilliant article on using Liquid Templates to return JSON, I would like to demonstrate creating and using a ‘service’ to asynchronously retrieve Dynamics 365 data into any portal page.

Why is this useful?

Liquid Templates tags are rendered on server side before a response is returned to the browser, so FetchXML tag will return a static result once the page is returned.
But what about responding dynamically to client side events such as option selection, button click or expending an element to view more details?
Sending the page to the server again is no longer an option if you want to maintain a decent UX. Having an endpoint that can be called asynchronously to return data from Dynamics 365 can certainly help here. The next walkthrough explains how to do just that.
In Part 2, I’ll demonstrate a similar service aimed to support Retrieve requests (rather than RetrieveMultiple).

  1. Create a Web Template named FetchXMLServiceMake sure that the Mime Type is set to application/json

    Create Web Template

    Paste the following code in to the web template source and save

    {% comment %} test for required FetchXML query {% endcomment %}
    {% if request.params[‘query’] %}
    {% capture msg_no_data %}No data or attribute was not included in query{% endcapture %}
    {% comment %} get FetchXML query from request params, decode query XML and execute query {% endcomment %}
    {% fetchxml query %}
    {{ request.params[‘query’] | replace: ‘%3C’, ‘<‘ | replace: ‘%20’, ‘ ‘ | replace: ‘%3D’, ‘=’ | replace: ‘%3E’, ‘>’ | replace: ‘%2F’, ‘/’ }}
    {% endfetchxml %}
    {% comment %} parse requested attributes into array {% endcomment %}
    {% assign columnset = request.params[‘columnset’] | split: “,” %}
    {% comment %} Emit JSON response {% endcomment %}
    {
    “totalcount”: {{ query.results.total_record_count }},
    “morerecords”: {{ query.results.more_records }},
    “results”: [
    {% for item in query.results.entities %}
    {
    {% comment %} Iterate throguh requestd attributes array {% endcomment %}
    {% for att in columnset %}
    {% comment %} Handle optionset attribute {% endcomment %}
    {% if item[att].label %}”{{ att }}”:”{{ item[att].label | default: msg_no_data }}”
    {% comment %} Handle lookup attribute {% endcomment %}
    {% elseif item[att].name %}”{{ att }}”:{“name”:”{{ item[att].name | default: msg_no_data }}”,”id”:”{{ item[att].id | default: msg_no_data }}”}
    {% comment %} Handle other attributes {% endcomment %}
    {% else %}”{{ att }}”:”{{ item[att] | default: msg_no_data }}”
    {% endif %}{% unless forloop.last %},{% endunless %}
    {% endfor -%}
    }
    {% unless forloop.last %},{% endunless %}{% endfor -%}
    ]
    }
    {% comment %} handle no FetchXML query {% endcomment %}
    {% else %}
    { “error”:”No FetchXML query” }
    {% endif %}
  2. Create a Page Template named FetchXMLService 

    Map the Page Template to the Web Template created on step 1 above.
    Uncheck the Header and Footer checkbox.Create page template

  3. Create a Portal Page named FetchXMLService 

    Set Home as parent page.
    Map the page to the FetchXMLService Page Template and copy the partial URL which is used in the next stepcreate page

  4. Consume Service 

    Use the following code sample anywhere you need asynchronously retrieval of data from Dynamics 365. In my example it is located in the Home page JavaScript portion.
    Note the URL address which maps to the Page (created above) URL.
    Replace the FetchXML query with your own query and specify the attributes you want to get values.
    Most important: make sure your users have the required Entity Permissions for the entities queried, otherwise they will receive empty results.

    $(function (){
    //define asynchronous request from any portal page
    $.ajax({
    method: “POST”,
    url: “/fetchxmlservice/“,
    data: {
    //define FetchXML query
    query: encodeURIComponent(
    “<fetch count=’10’ returntotalrecordcount=’true’>” +
    “<entity name=’incident’>” +
    “<attribute name=’ticketnumber’/>” +
    “<attribute name=’prioritycode’ />” +
    “<attribute name=’title’ />” +
    “<attribute name=’createdon’/>” +
    “<attribute name=’customerid’/>” +
    “<attribute name=’ownerid’/>” +
    “<attribute name=’statecode’/>” +
    “<attribute name=’incidentid’/>” +
    “<attribute name=’caseorigincode’/>” +
    “<order attribute=’title’ descending=’false’ />” +
    “</entity>” +
    “</fetch>”
    ),
    //define attributes collection to return values from query
    columnset: “ticketnumber,title,createdon,incidentid,statecode,caseorigincode,customerid,ownerid
    }
    }).done(function (msg){
    console.log(msg);
    }).fail(function (jqXHR, textStatus, errorThrown){
    console.log(textStatus);
    });
    });

    As the sample code logs the resulting JSON object to the console, open the browser developers tool (F12) to view it.

returend object

Implementation Notes

  • The service is useful for simple FetchXML queries. For more complex queries including linked entities, you’ll need to upgrade the Web Template code to handle more complex query results
  • Liquid Templates language includes a url_decode function but it seem unavailable in the Portal language variation. Hence the explicit decoding in the Web Template