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 TemplatePaste 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 FetchXMLServiceMap 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 FetchXMLServiceSet 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 ServiceUse 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.

    $(function (){
      //define asynchronous request from any portal page
    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>” +
    //define attributes collection to return values from query
    columnset: “ticketnumber,title,createdon,incidentid,statecode,caseorigincode,customerid,ownerid
    }).done(function (msg){
    }).fail(function (jqXHR, textStatus, errorThrown){

    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