Quantcast
Channel: Web API - Microsoft Dynamics 365 CRM Tips and Tricks
Viewing all 33 articles
Browse latest View live

Execute fetchxml using Web API in Dynamics CRM 2016

$
0
0

Introduction

Microsoft Dynamics CRM Online 2016 Update and Microsoft Dynamics CRM 2016 (on-premises) introduced new concept called The Web API. It can be used across a wide variety of programming languages, platforms, and devices. The Web API implements the OData (Open Data Protocol), version 4.0, an OASIS standard for building and consuming Restful APIs.

Basically Web API is advanced version of old OData. With the help of Web API you can perform following operation.

  • Create
  • Update
  • Delete
  • Retrieve
  • Retrieve multiple( using odata query and fetch)
  • Execute Web API functions
  • Execute Web API Actions
  • Execute Web API Query Functions

Walkthrough

As earlier version of Odata does not support to execute the fetchxml. To execute fetchxml you have to use SOAP. Now using Web API you can execute the fetchxml.

Below is example that used to execute the fetchxml.

First define your fetchxml and execute using Web API using following code.

If you want retrieve formatted value and data about lookup properties. You have add following line in request header.

xhr.setRequestHeader("Prefer", "odata.include-annotations=*");

Below is the entire code.

// This function is used to retrieve records using fetchxml
            fetch: function (originalFetch, entitySetName, retrieveUsingFetchSuccess, retrieveUsingFetchError) {

                var fetch = null;
                try {
                    //create the fetch
                    fetch = ["<fetch mapping='logical'>", originalFetch, "</fetch>"].join("");
                    //encode the fetchxml
                    fetch = escape(fetch);
                    //create AJAX request
                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        //async: false,
                        url: this.getWebAPIPath() + entitySetName + "?fetchXml=" + fetch,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; odata.metadata=minimal");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                            ////xhr.setRequestHeader("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
                        },
                        success: function (data, textStatus, xhr) {

                            if (data != null) {

                                var entityObj = [];                              
                                var pagingInfo = null;

                                //Check if results contains cookies 
                                //if yes then retrieve next set of records
                                if (data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"] != null) {

                                    //get the pagingcookie
                                    pagingInfo = Inogic.ApiLib.getPagingCookie(data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"]);
                                
                                    //call this function create json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    //call this to retrieve more records
                                    Inogic.ApiLib.fetchMore(originalFetch, entitySetName, retrieveUsingFetchSucess, retrieveUsingFetchError,pagingInfo.pageCokies,pagingInfo.pageNumber, entityObj);

                                }
                            }
                                //get the results and create json object
                            else {

                                var entityObj = [];

                                // This function is used to create the json object
                                Inogic.ApiLib.createJsonObject(data, entityObj);

                                //call successcallback
                                retrieveUsingFetchSuccess(entityObj);
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            retrieveUsingFetchError(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }

            };

Web API return 5000 records at time, to retrieve more than 5000 records you have to use paging cookie. To identify more records you can use @Microsoft.Dynamics.CRM.fetchxmlpagingcookie. If query has more records then @Microsoft.Dynamics.CRM.fetchxmlpagingcookie contains value. The format of it given below

var  pagingcookie = data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];
pagingcookie = "<cookie pagenumber="2" pagingcookie="%253ccookie%2520page%253d%25221%2522%253e%253caccountid%2520last%253d%2522%257b133D006A-E89C-E511-80D8-F0921C194348%257d%2522%2520first%253d%2522%257b46A60D62-BF9C-E511-80DD-6C3BE5A8DACC%257d%2522%2520%252f%253e%253c%252fcookie%253e" istracking="False" />"
You have decode this using "unescape".  
pagingcookie = unescape(pagingcookie;)
When you decode then will looks like below.
pagingcookie  = "<cookie pagenumber="2" pagingcookie="<cookie page="1"><accountid last="{133D006A-E89C-E511-80D8-F0921C194348}" first="{46A60D62-BF9C-E511-80DD-6C3BE5A8DACC}" /></cookie>" istracking="False" />"

From above pagingcookie  you can extract the cookie part & pagenumber and add this to fetchxml  and pass this updated fetchxml to retrieve more records.

When you execute fetch it return data in json format.

To get the value of from result use following code.

  1. String/Number etc

var name = data.value[0].name;

  1. Lookup(Entity Reference)

id: data.value[0]._primarycontactid_value,

name: data.value[0]["_primarycontactid_value@OData.Community.Display.V1.FormattedValue"],

logicalname: data.value[0]["_primarycontactid_value@Microsoft.Dynamics.CRM.lookuplogicalname"],

  1. Option set/Money/DataTime/Boolean

value: data.value[0].revenue

formattedValue :data.value[0]["revenue@OData.Community.Display.V1.FormattedValue"]

Since there were requests to include the code in the API, I have added the code of the functions used here. This is our implementation and not necessarily the only or the best way to have it developed. We have been using XrmServiceToolkit for a while and the code here is a similar implementation for WEB API.

//This function is used to get paging cookies
            getPagingCookie: function (pageCokies) {
                var pagingInfo = {};
                var pageNumber = null;

                try {
                    //get the page cokies
                    pageCokies = unescape(unescape(pageCokies));

                    //get the pageNumber
                    pageNumber = parseInt(pageCokies.substring(pageCokies.indexOf("=") + 1, pageCokies.indexOf("pagingcookie")).replace(/\"/g, '').trim());

                    // this line is used to get the cookie part
                    pageCokies = pageCokies.substring(pageCokies.indexOf("pagingcookie"), (pageCokies.indexOf("/>") + 12));
                    pageCokies = pageCokies.substring(pageCokies.indexOf("=") + 1, pageCokies.length);
                    pageCokies = pageCokies.substring(1, pageCokies.length - 1);

                    //replace special character 
                    pageCokies = pageCokies.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '\'').replace(/\'/g, '&' + 'quot;');

                    //append paging-cookie
                    pageCokies = "paging-cookie ='" + pageCokies + "'";

                    //set the parameter
                    pagingInfo.pageCokies = pageCokies;
                    pagingInfo.pageNumber = pageNumber;

                } catch (e) {
                    throw new Error(e);
                }

                return pagingInfo;
            },

            // This function is used to fetchmore records
            fetchMore: function (originalFetch, entitySetName, retrieveUsingFetchSucess, errorCallback, pageCookies, pageNumber, entityObj) {

                var fetch = null;
                try {

                    //add the pageCookies and pageNumber into FetchXML
                    var fetch = ["<fetch mapping='logical' page='" + pageNumber + "' " + pageCookies + ">", originalFetch, "</fetch>"].join("");

                    //encode the fetchxml
                    fetch = escape(fetch);

                    //Create AJAX request
                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        //async: false,
                        url: this.getWebAPIPath() + entitySetName + "?fetchXml=" + fetch,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; odata.metadata=minimal");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                            ////xhr.setRequestHeader("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
                        },
                        success: function (data, textStatus, xhr) {

                            if (data != null) {

                                var pagingInfo = null;

                                //Check if results contains cookies 
                                //if yes then retrieve next set of records
                                if (data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"] != null) {

                                    //get the pagingcookie
                                    pagingInfo = Inogic.ApiLib.getPagingCookie(data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"]);

                                    //call this function create json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    //call this to retrieve more records
                                    Inogic.ApiLib.fetchMore(originalFetch, entitySetName, retrieveUsingFetchSucess, retrieveUsingFetchError, pagingInfo.pageCokies, pagingInfo.pageNumber, entityObj);

                                }
                                else {

                                    // This function is used to create the json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    retrieveUsingFetchSucess(entityObj);
                                }
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);

                }
            },

Conclusion

In this way, We can use Web API to execute fetchxml instead of SOAP.

Before you move on to the next post, check our Maplytics InfoCenter.


Querying data in Microsoft Dynamics CRM 2016 using Web API

$
0
0

Introduction:

With Microsoft Dynamics CRM 2016, Web API that was in Preview for CRM 2015 is now GA. Web API is really ODATA v4 which is the later version of ODATA v2 that was implemented in earlier versions of CRM until CRM 2015.

With CRM 2016, ODATA v2 is deprecated, this means that though the legacy code written using ODATA v2 will continue to function, it is not advised to continue to develop using this version of ODATA starting CRM 2016.

The earlier version of ODATA was strictly restricted to CRUD operations, how with Web API you can even perform operations that earlier required us to use SOAP requests.

In the earlier post, it was all about executing FetchXML queries using Web API, well that was to some extent because I didn’t have much success querying and applying some very common queries. After spending some more time with WEB API and trying to get things done exclusively using ODATA v4, I did get quite a few things figured out.

In this post, I am listing out some of the frequently used queries and how these could be generated using Web API.

ODATA v4 endpoints:

Under Developer Resources you can now find the endpoint for web api

Querying data in Microsoft Dynamics CRM 2016

Notice the change in the URL structure, it is now /api/data/v8.0/

Earlier it was /xrmservices/2011/organizationdata.svc/

Sample Queries:

  1. List accounts starting with A and C

    var qry = “accounts?$filter=startswith(name,’A’) or startswith(name,’C’)”;

    Since field names have not been specified all the columns are listed.

    The entitycollection does not include Set Prefix anymore besides its using the logical name throughout.

  2. List accounts owned by a particular user

    var qry = accounts?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=_ownerid_value%20eq%201ea6fc32-9b2d-47e6-b9ab-b5f23f69e34f;

    Here we had to provide the guid of the user that you need to filter by. Also notice that the ownerid attribute has been mentioned as _ownerid_value

    All lookups are listed in the query result to follow the naming structure

    _<logicalname>_value.

  3. Read account details along with the primary contact phone.

    We need to use the $expand clause to request data of related entity. However it appears that the $expand clause only works when requesting data of a single record as shown in the below query.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=contains(name,'(sample)’)&$orderby=name&$expand=primarycontactid($select=fullname,telephone1)”

    If you were to request this for the entire accounts collection, you receive the following error message

    {
    
    "error":{
    
    "code":"","message":"Expansion of navigation properties isn\u2019t supported on entity collections.","innererror":{
    
    "message":"Expansion of navigation properties isn\u2019t supported on entity collections.","type":"Microsoft.Crm.CrmHttpException","stacktrace":" at

  4. List all Phone Calls of an account

    This will display only the subject of the related phone calls.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$expand=Account_Phonecalls($select=subject)”

Understand the Query Results

Unlike the ODATA v2 queries, the results here are returned in JSON format

{

"@odata.context":"https://dyn20161.crm5.dynamics.com/api/data/v8.0/$metadata#accounts(name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue)","value":[

"@odata.etag":"W/\"632098\"","name":"Alpine Ski House (sample)","accountnumber":"ABCO9M32","_primarycontactid_value":"1cf3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":90000.0000,"accountid":"4cf2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

},{

"@odata.etag":"W/\"632065\"","name":"A. Datum Corporation (sample)","accountnumber":null,"_primarycontactid_value":"1ef3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":10000.0000,"accountid":"4ef2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

}

]

}

Now if see the results here, the primary contact id only provides the Guid, not really helpful, and for currency data types, it again returns only the number, the currency is provided as transaction guid, so again formatted value missing.

If we want the results to return the formatted values, we need to pass the following in the header tag of the request

odata.include-annotations=”OData.Community.Display.V1.FormattedValue”

I haven’t figured it out how to pass these in the browser url, but here is the code I use to pass the header values.

var qry = url;

var headers = {


'Content-Type': 'application/json',

Accept: 'application/json', 'OData-MaxVersion': 4.0,

Prefer: 'odata.include-annotations="*", odata.maxpagesize=3'

};

var request = {

requestUri: qry,

method: 'GET',

headers: headers,

data: null

};

 
odatajs.oData.request(

request,

successCallback,

errorCallback);

In the above code you can replace the “*” with “OData.Community.Display.V1.FormattedValue”, the other preferences supported are

Microsoft.Dynamics.CRM.lookuplogicalname

Microsoft.Dynamics.CRM.associatednavigationproperty

Generally for lookups, we are used to receiving 3 set of data,

The lookup entity name, the guid and the record name. By default we only received the Guid of a lookup field, if we need the record name and the entity name, we need to include the preferences listed above.

If you want all preferences to be applied pass “*”

With all preferences the applied the result would appear as

Querying data in CRM 2016 using Web API

Lookup field details are available as shown above

_primarycontactid_value: “1ef3c099-bca1-e511-80de-3863bb349a78″

_primarycontactid_value@Microsoft.Dynamics.CRM.associatednavigationproperty: “primarycontactid”

_primarycontactid_value@Microsoft.Dynamics.CRM.lookuplogicalname: “contact”

_primarycontactid_value@OData.Community.Display.V1.FormattedValue: “Rene Valdes (sample)”

And we now also get the revenue formatted with the currency symbol and the date.

Paging

To handle paging you need to specify the page size, which is now called odata.maxpagesize=n

N stands for the count of records to be returned.

You also receive the paging cookie, which will allow you to request the next set of records.

 Web API

Use the nextlink url to the Web API to request the next set of data. It returns a fully qualified url with the query parameters set that can be used just as is.

Result Count

When you include the $count=true in your query, you get the total count of the records returned by the query in the query result.

If you query the following,

var qry5 = “https://xxx.crm5.dynamics.com/api/data/v8.0/accounts?$count=true&$top=2″

You get

Querying data in Dynamics CRM 2016 using Web API

The total count is 19 even though the results requested were only top 2

Note, if there are more than 5000 records that the query returns, the count here would still return 5000 only.

Conclusion

The Web API query still has a few limitations and like the earlier ODATA v2 there are limitations on what kind of data can be queried. You can find the complete list here

In this post I have covered queries, in the later blogs hope to cover the other operations supported by WEB API.

Make your Dynamics CRM life easy with Inogic Dynamics CRM Solutions. Read more about our add-ons here.

Web API Actions in Dynamics CRM 2016

$
0
0

Taking forward our series on using WEB API in Microsoft Dynamics CRM 2016, we will now touch upon a feature that was not available in ODATA v2 of the earlier versions.

ODATA v2 only provided support for CRUD operations. But Dynamics CRM has some special messages/functions for special operations that are beyond the basic CRUD on an entity. To perform these actions in the earlier versions of Microsoft Dynamics CRM, we had to fall back on SOAP messages.

With Web API, actions are now supported. Action is equivalent to requests that are available in Dynamics CRM.

There are predefined Actions defined in Dynamics CRM 2016 that can be executed using Web API. Following is like where you will find the list of Web API actions. https://msdn.microsoft.com/en-in/library/mt607829.aspx

There are three types of Action as listed below.

  1. Unbound actions: It is not bound to any specific entity. i.e the first parameter to such actions does not include the entity. E.g. WinOpportunity, CancelContract etc
  2. Bound actions: It is bound to specific entity. i.e the first parameter to such actions does not include the entity. e.g. – AddToQueue Action
  3. Custom action: It is custom actions developed by developers using Processes.

We are explaining Web API Action called ConvertSalesOrderToInvoice which corresponds to the organization service ConvertSalesOrderToInvoiceRequest. ConvertSalesOrderToInvoice action is not bound to any entity and does not return a value. ConvertSalesOrderToInvoice Action require following parameters.

SalesOrderId: Guid of the order to convert. (This is compulsory parameter)

ColumnSet: List of attributes to retrieve from the created invoice. (This is compulsory parameter)

Below is the code that are used to execute ConvertSalesOrderToInvoice Action.

//This function is used execute the standard action of webAPI

Here is the main Ajax request that execute the Action.

function executeAction() {

    var saleOrderID = null;

    var columnsSet = null;

    try {      

        //set the param values

        saleOrderID = "D035DD97-3AB5-E511-80E2-6C3BE5A852B0"; 

        columnsSet = new Array("name", "totalamount");      

        //create the action object

        var actionObj = {

            "SalesOrderId": saleOrderID,

            "ColumnSet":

                {

'AllColumns': false,

                    'Columns': columnsSet

                },

        };

        // call this function to execute the action. Please note the () used along with the function name

        Inogic.ApiLib.execute(actionObj, "ConvertSalesOrderToInvoice()", function (data) {

            // open the Created invoice record

            Xrm.Utility.openEntityForm("invoice", data.invoiceid);           

        }, function (error) { throw new Error(error.message);

    } catch (e) {

        alert(e.message);

    }

}

//This function is used to execute the Web API Action

            execute: function (req, reqName, successCallback, errorCallback) {

                //create AJAX request

                $.ajax({

                    type: "POST",

                    contentType: "application/json; charset=utf-8",

                    datatype: "json",

                    url: encodeURI(this.getWebAPIPath() + reqName),

                    data: window.JSON.stringify(req),

                    beforeSend: function (xhr) {

                        //Specifying this header ensures that the results will be returned as JSON.            

                        xhr.setRequestHeader("Accept", "application/json");

                        xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");

                        xhr.setRequestHeader("OData-MaxVersion", "4.0");

                        xhr.setRequestHeader("OData-Version", "4.0");

                    },

                    success: function (data, textStatus, xhr) {

                        //successCallback function

                        successCallback(data);

                    },

                    error: function (xhr, textStatus, errorThrown) {

                        errorCallback(Inogic.ApiLib.errorHandler(xhr));

                    }});

            },

//This function is used to get the client URL

   getClientUrl: function () {

                //Get the organization URL

                if (typeof GetGlobalContext == "function" &&

                    typeof GetGlobalContext().getClientUrl == "function") {

                    return GetGlobalContext().getClientUrl();

                }               

            }

Similar to this you can execute any Web API actions that are listed and your custom action that you developed.

Conclusion:

Web API can be used for executing messages other than CRUD as well.

Everything in Maplytics – Dynamics CRM and Bing Maps integration is now a search away at our Maplytics InfoCentre.

Web API functions in Dynamics CRM 2016

$
0
0

The Web API which is introduced in Microsoft Dynamics CRM 2016 enhances the experience while developing through different programming languages, devices and platforms. It implements the OData, version 4.0, an OASIS standard which is used to build as well as to consume RESTful APIs over rich data sources.

There are predefined functions introduced in the Web API which when executed help you to retrieve data. They may have parameters and they may return values. Functions may be bound to a specific entity. You will find the list of Web API functions on the web page: https://msdn.microsoft.com/en-us/library/mt607866.aspx.

Let’s take an example of RetrieveVersion function

The RetrieveVersion function is used to get the version number of Microsoft Dynamics CRM Server. It is similar to the RetrieveVersionRequest which is used to get the version number through organization services.

The function is not bound to any entity types and does not require any parameters.

Here is the code for executing the standard functions of the WebAPI.

//This function is used execute the standard functions of webAPI

function exeFunction() {
    try {
        Inogic.ApiLib.executeFunction("RetrieveVersion()", exeFunctionSucess, function(error){throw new Error(error.message)};

    } catch (e) {
        showMessage(e.message);
    }
}

//success call back
function exeFunctionSucess(data) {
    try {

        var versionNumber = data;
    }
    catch (e) {
        showMessage(e.message);
    }
}

Here is the main code for executing the functions and fetching the results.

// This function is used to execute the function and get the results
 
            executeFunction: function (funName, successCallback, errorCallback) {

                //create the AJAX request
                $.ajax({
                    type: "GET",
                    contentType: "application/json; charset=utf-8",
                    datatype: "json",                  
                    url: encodeURI(this.getWebAPIPath() + funName),                   
                    beforeSend: function (xhr) {
                        
// This header ensures that the results will be returned as JSON.   
          
                        xhr.setRequestHeader("Accept", "application/json");                    
                     
//xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");

                        xhr.setRequestHeader("OData-MaxVersion", "4.0");
                        xhr.setRequestHeader("OData-Version", "4.0");
                    },
                    success: function (data, textStatus, xhr) {

                        //successCallback function - Here you get the version number.

                        successCallback(data.Version);
                    },
                    error: function (xhr, textStatus, errorThrown) {
                        errorCallback(Inogic.ApiLib.errorHandler(xhr));
                    }
                });

            }

Web API Query Functions:

Query functions are those which are used to add a filter criteria in Odata query. These functions accept parameters and return a Boolean value. It serves to be an additional filter applied on Odata query.

You would find predefined query functions of Web API in the following link. https://msdn.microsoft.com/en-us/library/mt607843.aspx

Let us consider ThisYear Function. It is used to retrieve data within the current year. It accepts parameter as property name (date attribute name) and returns data within this year.

Note: This function only accepts Date Datatype as a parameter. If you pass a parameter other than the date, then it throws an error.

// This function is used to execute the query function 

function executeQueryFunction() {

    var query = null;

    try {

        // create the query

        query = "?$select=accountcategorycode,accountnumber,creditonhold,createdon,numberofemployees,name,revenue";

        // add the query function
 
        query += "&$filter=Microsoft.Dynamics.CRM.ThisYear(PropertyName='modifiedon')";

        //query += "&$filter=Microsoft.Dynamics.CRM.Today(PropertyName='modifiedon')";

        //call this function to execute the query function
        Inogic.ApiLib.executeQueryFunction("accounts", query, executeQueryFunctionSuccess, executeQueryFunctionError, executeQueryFunctionError, false);

    } catch (e) {
        showMessage(e.message);
    }
}

//success call back

function executeQueryFunctionSuccess(data) {
    try {

        //This function is used to process return data

        processData(data);

        HideBusyIndicator();
    }
    catch (e) {
        showMessage(e.message);
    }
}

This is the main Ajax call function.

// This function is used to retrieve records using WebAPI query function

            executeQueryFunction: function (entitySetName, query, successCallback, errorCallback, onComplete) {

                try {
                
                    //create AJAX request

                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        url: encodeURI(oDataUrl),
                        beforeSend: function (xhr) {
                           
//This header ensures that the results will be returned as JSON. 

                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");                          
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");

                        },
                        success: function (data, textStatus, xhr) {
                            if (data != null) {
                                successCallback(data.value);                              
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(xhr.statusText);
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }

            },

When you execute the above query then it will return all Accounts which are modified during a particular year.

Before moving on to the next post, you may like to read about Dynamics CRM and Bing Maps integration.

Impersonation available using WEB API in Dynamics CRM 2016

$
0
0

Introduction:

Microsoft Dynamics CRM online 2016 update and Dynamics CRM 2016 (on-premises) has introduced a new concept called the Web API. This can be used across a wide variety of programming languages, platforms, and devices. One of the features of Web API is Impersonation.

Back in the days of CRM 4, Impersonation through scripting was supported by including the impersonation details in the header of the SOAP request.

Later this feature was removed and there was no way to impersonate a user through Scripting.

Impersonation is used when you want to execute business logic (code) on behalf of another CRM user. This is necessary because the CRM Web services can be called by various clients and services on behalf of a CRM user. Impersonation involves two different users where User (X) is used for executing the code to perform some tasks on behalf of another user (Y).

Walkthrough of Impersonation through Script

The User account (X) has to be given the prvActOnBehalfOfAnotherUser privilege to perform the task.

In order to impersonate a user through the Web API, you need to add ‘MSCRMCallerID’ key with GUID of the impersonated user. In the below example, a new contact entity is created on behalf of the user with systemuserid B65AB846-7EBE-E511-80DF-00155D06F307.

Here’s the code which helps you to impersonate a user through the Web API.

function impersonateUserReq()
{
    var userID = null;

    try {

        // create the contact object
        var contact = new Object();
        contact.firstname = "FirstName";
        contact.lastname = "LastName";
        contact.accountrolecode = 2;
        contact.creditonhold = false;
        contact["parentcustomerid_account@odata.bind"] = "/accounts(89C202DF-B1AF-E511-80E9-00155D06D000)"

        ///set the impersonateUser userid -  
        userID = "B65AB846-7EBE-E511-80DF-00155D06F307";

        Inogic.ApiLib.impersonateUser("contacts", contact, userID,
           impersonateUserSuccess,
           impersonateUserError);
    } catch (e) {
        showMessage(e.message);
    }
}
      // this Actual ajax request function is used to create the record and impersonate the user
            impersonateUser: function (entitySetName, entity,userId, successCallback, errorCallback) {

                var jsonEntity = null;

                try {

                    //create json object
                    var jsonEntity = window.JSON.stringify(entity);

                    //create AJAX request
                    $.ajax({
                        type: "POST",                      
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        url: encodeURI(this.getWebAPIPath() + entitySetName),
                        data: jsonEntity,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.            
                        
                            xhr.setRequestHeader("MSCRMCallerID", userId);
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                        },
                        success: function (data, textStatus, xhr) {

                            //call successCallback
                            successCallback(xhr.getResponseHeader("OData-EntityId"));
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }
            },

In the above code, the only addition is the following line of code

   xhr.setRequestHeader("MSCRMCallerID", userId);

Once the callerid is set, the record is created using the privileges that is assigned to the user specified in the callerid rather than the logged in user.

Conclusion:

On a concluding note, impersonation helps to perform operations on behalf of other users if the system account running the code has the necessary privileges.

You may also like to read : Make your Dynamics CRM life easy with Inogic Dynamics CRM Solutions.

Execute fetchxml using Web API in Dynamics CRM 2016

$
0
0

Introduction

Microsoft Dynamics CRM Online 2016 Update and Microsoft Dynamics CRM 2016 (on-premises) introduced new concept called The Web API. It can be used across a wide variety of programming languages, platforms, and devices. The Web API implements the OData (Open Data Protocol), version 4.0, an OASIS standard for building and consuming Restful APIs.

Basically Web API is advanced version of old OData. With the help of Web API you can perform following operation.

  • Create
  • Update
  • Delete
  • Retrieve
  • Retrieve multiple( using odata query and fetch)
  • Execute Web API functions
  • Execute Web API Actions
  • Execute Web API Query Functions

Walkthrough

As earlier version of Odata does not support to execute the fetchxml. To execute fetchxml you have to use SOAP. Now using Web API you can execute the fetchxml.

Below is example that used to execute the fetchxml.

First define your fetchxml and execute using Web API using following code.

If you want retrieve formatted value and data about lookup properties. You have add following line in request header.

xhr.setRequestHeader("Prefer", "odata.include-annotations=*");

Below is the entire code.

// This function is used to retrieve records using fetchxml
            fetch: function (originalFetch, entitySetName, retrieveUsingFetchSuccess, retrieveUsingFetchError) {

                var fetch = null;
                try {
                    //create the fetch
                    fetch = ["<fetch mapping='logical'>", originalFetch, "</fetch>"].join("");
                    //encode the fetchxml
                    fetch = escape(fetch);
                    //create AJAX request
                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        //async: false,
                        url: this.getWebAPIPath() + entitySetName + "?fetchXml=" + fetch,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; odata.metadata=minimal");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                            ////xhr.setRequestHeader("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
                        },
                        success: function (data, textStatus, xhr) {

                            if (data != null) {

                                var entityObj = [];                              
                                var pagingInfo = null;

                                //Check if results contains cookies 
                                //if yes then retrieve next set of records
                                if (data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"] != null) {

                                    //get the pagingcookie
                                    pagingInfo = Inogic.ApiLib.getPagingCookie(data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"]);
                                
                                    //call this function create json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    //call this to retrieve more records
                                    Inogic.ApiLib.fetchMore(originalFetch, entitySetName, retrieveUsingFetchSucess, retrieveUsingFetchError,pagingInfo.pageCokies,pagingInfo.pageNumber, entityObj);

                                }
                            }
                                //get the results and create json object
                            else {

                                var entityObj = [];

                                // This function is used to create the json object
                                Inogic.ApiLib.createJsonObject(data, entityObj);

                                //call successcallback
                                retrieveUsingFetchSuccess(entityObj);
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            retrieveUsingFetchError(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }

            };

Web API return 5000 records at time, to retrieve more than 5000 records you have to use paging cookie. To identify more records you can use @Microsoft.Dynamics.CRM.fetchxmlpagingcookie. If query has more records then @Microsoft.Dynamics.CRM.fetchxmlpagingcookie contains value. The format of it given below

var  pagingcookie = data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];
pagingcookie = "<cookie pagenumber="2" pagingcookie="%253ccookie%2520page%253d%25221%2522%253e%253caccountid%2520last%253d%2522%257b133D006A-E89C-E511-80D8-F0921C194348%257d%2522%2520first%253d%2522%257b46A60D62-BF9C-E511-80DD-6C3BE5A8DACC%257d%2522%2520%252f%253e%253c%252fcookie%253e" istracking="False" />"
You have decode this using "unescape".  
pagingcookie = unescape(pagingcookie;)
When you decode then will looks like below.
pagingcookie  = "<cookie pagenumber="2" pagingcookie="<cookie page="1"><accountid last="{133D006A-E89C-E511-80D8-F0921C194348}" first="{46A60D62-BF9C-E511-80DD-6C3BE5A8DACC}" /></cookie>" istracking="False" />"

From above pagingcookie  you can extract the cookie part & pagenumber and add this to fetchxml  and pass this updated fetchxml to retrieve more records.

When you execute fetch it return data in json format.

To get the value of from result use following code.

  1. String/Number etc

var name = data.value[0].name;

  1. Lookup(Entity Reference)

id: data.value[0]._primarycontactid_value,

name: data.value[0]["_primarycontactid_value@OData.Community.Display.V1.FormattedValue"],

logicalname: data.value[0]["_primarycontactid_value@Microsoft.Dynamics.CRM.lookuplogicalname"],

  1. Option set/Money/DataTime/Boolean

value: data.value[0].revenue

formattedValue :data.value[0]["revenue@OData.Community.Display.V1.FormattedValue"]

Since there were requests to include the code in the API, I have added the code of the functions used here. This is our implementation and not necessarily the only or the best way to have it developed. We have been using XrmServiceToolkit for a while and the code here is a similar implementation for WEB API.

//This function is used to get paging cookies
            getPagingCookie: function (pageCokies) {
                var pagingInfo = {};
                var pageNumber = null;

                try {
                    //get the page cokies
                    pageCokies = unescape(unescape(pageCokies));

                    //get the pageNumber
                    pageNumber = parseInt(pageCokies.substring(pageCokies.indexOf("=") + 1, pageCokies.indexOf("pagingcookie")).replace(/\"/g, '').trim());

                    // this line is used to get the cookie part
                    pageCokies = pageCokies.substring(pageCokies.indexOf("pagingcookie"), (pageCokies.indexOf("/>") + 12));
                    pageCokies = pageCokies.substring(pageCokies.indexOf("=") + 1, pageCokies.length);
                    pageCokies = pageCokies.substring(1, pageCokies.length - 1);

                    //replace special character 
                    pageCokies = pageCokies.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '\'').replace(/\'/g, '&' + 'quot;');

                    //append paging-cookie
                    pageCokies = "paging-cookie ='" + pageCokies + "'";

                    //set the parameter
                    pagingInfo.pageCokies = pageCokies;
                    pagingInfo.pageNumber = pageNumber;

                } catch (e) {
                    throw new Error(e);
                }

                return pagingInfo;
            },

            // This function is used to fetchmore records
            fetchMore: function (originalFetch, entitySetName, retrieveUsingFetchSucess, errorCallback, pageCookies, pageNumber, entityObj) {

                var fetch = null;
                try {

                    //add the pageCookies and pageNumber into FetchXML
                    var fetch = ["<fetch mapping='logical' page='" + pageNumber + "' " + pageCookies + ">", originalFetch, "</fetch>"].join("");

                    //encode the fetchxml
                    fetch = escape(fetch);

                    //Create AJAX request
                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        //async: false,
                        url: this.getWebAPIPath() + entitySetName + "?fetchXml=" + fetch,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; odata.metadata=minimal");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                            ////xhr.setRequestHeader("Prefer", "odata.include-annotations=OData.Community.Display.V1.FormattedValue");
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
                        },
                        success: function (data, textStatus, xhr) {

                            if (data != null) {

                                var pagingInfo = null;

                                //Check if results contains cookies 
                                //if yes then retrieve next set of records
                                if (data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"] != null) {

                                    //get the pagingcookie
                                    pagingInfo = Inogic.ApiLib.getPagingCookie(data["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"]);

                                    //call this function create json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    //call this to retrieve more records
                                    Inogic.ApiLib.fetchMore(originalFetch, entitySetName, retrieveUsingFetchSucess, retrieveUsingFetchError, pagingInfo.pageCokies, pagingInfo.pageNumber, entityObj);

                                }
                                else {

                                    // This function is used to create the json object
                                    Inogic.ApiLib.createJsonObject(data, entityObj);

                                    retrieveUsingFetchSucess(entityObj);
                                }
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);

                }
            },

Conclusion

In this way, We can use Web API to execute fetchxml instead of SOAP.

Before you move on to the next post, check our Maplytics InfoCenter.

Querying data in Microsoft Dynamics CRM 2016 using Web API

$
0
0

Introduction:

With Microsoft Dynamics CRM 2016, Web API that was in Preview for CRM 2015 is now GA. Web API is really ODATA v4 which is the later version of ODATA v2 that was implemented in earlier versions of CRM until CRM 2015.

With CRM 2016, ODATA v2 is deprecated, this means that though the legacy code written using ODATA v2 will continue to function, it is not advised to continue to develop using this version of ODATA starting CRM 2016.

The earlier version of ODATA was strictly restricted to CRUD operations, how with Web API you can even perform operations that earlier required us to use SOAP requests.

In the earlier post, it was all about executing FetchXML queries using Web API, well that was to some extent because I didn’t have much success querying and applying some very common queries. After spending some more time with WEB API and trying to get things done exclusively using ODATA v4, I did get quite a few things figured out.

In this post, I am listing out some of the frequently used queries and how these could be generated using Web API.

ODATA v4 endpoints:

Under Developer Resources you can now find the endpoint for web api

Querying data in Microsoft Dynamics CRM 2016

Notice the change in the URL structure, it is now /api/data/v8.0/

Earlier it was /xrmservices/2011/organizationdata.svc/

Sample Queries:

  1. List accounts starting with A and C

    var qry = “accounts?$filter=startswith(name,’A’) or startswith(name,’C’)”;

    Since field names have not been specified all the columns are listed.

    The entitycollection does not include Set Prefix anymore besides its using the logical name throughout.

  2. List accounts owned by a particular user

    var qry = accounts?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=_ownerid_value%20eq%201ea6fc32-9b2d-47e6-b9ab-b5f23f69e34f;

    Here we had to provide the guid of the user that you need to filter by. Also notice that the ownerid attribute has been mentioned as _ownerid_value

    All lookups are listed in the query result to follow the naming structure

    _<logicalname>_value.

  3. Read account details along with the primary contact phone.

    We need to use the $expand clause to request data of related entity. However it appears that the $expand clause only works when requesting data of a single record as shown in the below query.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$select=name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue&$filter=contains(name,'(sample)’)&$orderby=name&$expand=primarycontactid($select=fullname,telephone1)”

    If you were to request this for the entire accounts collection, you receive the following error message

    {
    
    "error":{
    
    "code":"","message":"Expansion of navigation properties isn\u2019t supported on entity collections.","innererror":{
    
    "message":"Expansion of navigation properties isn\u2019t supported on entity collections.","type":"Microsoft.Crm.CrmHttpException","stacktrace":" at

  4. List all Phone Calls of an account

    This will display only the subject of the related phone calls.

    var qry = “accounts(4ef2c099-bca1-e511-80de-3863bb349a78)?$expand=Account_Phonecalls($select=subject)”

Understand the Query Results

Unlike the ODATA v2 queries, the results here are returned in JSON format

{

"@odata.context":"https://dyn20161.crm5.dynamics.com/api/data/v8.0/$metadata#accounts(name,accountnumber,_primarycontactid_value,createdon,accountcategorycode,revenue)","value":[

"@odata.etag":"W/\"632098\"","name":"Alpine Ski House (sample)","accountnumber":"ABCO9M32","_primarycontactid_value":"1cf3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":90000.0000,"accountid":"4cf2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

},{

"@odata.etag":"W/\"632065\"","name":"A. Datum Corporation (sample)","accountnumber":null,"_primarycontactid_value":"1ef3c099-bca1-e511-80de-3863bb349a78","createdon":"2015-12-13T17:12:15Z","accountcategorycode":null,"revenue":10000.0000,"accountid":"4ef2c099-bca1-e511-80de-3863bb349a78","_transactioncurrencyid_value":"5022ed92-bca1-e511-80e1-3863bb345aa8"

}

]

}

Now if see the results here, the primary contact id only provides the Guid, not really helpful, and for currency data types, it again returns only the number, the currency is provided as transaction guid, so again formatted value missing.

If we want the results to return the formatted values, we need to pass the following in the header tag of the request

odata.include-annotations=”OData.Community.Display.V1.FormattedValue”

I haven’t figured it out how to pass these in the browser url, but here is the code I use to pass the header values.

var qry = url;

var headers = {


'Content-Type': 'application/json',

Accept: 'application/json', 'OData-MaxVersion': 4.0,

Prefer: 'odata.include-annotations="*", odata.maxpagesize=3'

};

var request = {

requestUri: qry,

method: 'GET',

headers: headers,

data: null

};

 
odatajs.oData.request(

request,

successCallback,

errorCallback);

In the above code you can replace the “*” with “OData.Community.Display.V1.FormattedValue”, the other preferences supported are

Microsoft.Dynamics.CRM.lookuplogicalname

Microsoft.Dynamics.CRM.associatednavigationproperty

Generally for lookups, we are used to receiving 3 set of data,

The lookup entity name, the guid and the record name. By default we only received the Guid of a lookup field, if we need the record name and the entity name, we need to include the preferences listed above.

If you want all preferences to be applied pass “*”

With all preferences the applied the result would appear as

Querying data in CRM 2016 using Web API

Lookup field details are available as shown above

_primarycontactid_value: “1ef3c099-bca1-e511-80de-3863bb349a78″

_primarycontactid_value@Microsoft.Dynamics.CRM.associatednavigationproperty: “primarycontactid”

_primarycontactid_value@Microsoft.Dynamics.CRM.lookuplogicalname: “contact”

_primarycontactid_value@OData.Community.Display.V1.FormattedValue: “Rene Valdes (sample)”

And we now also get the revenue formatted with the currency symbol and the date.

Paging

To handle paging you need to specify the page size, which is now called odata.maxpagesize=n

N stands for the count of records to be returned.

You also receive the paging cookie, which will allow you to request the next set of records.

 Web API

Use the nextlink url to the Web API to request the next set of data. It returns a fully qualified url with the query parameters set that can be used just as is.

Result Count

When you include the $count=true in your query, you get the total count of the records returned by the query in the query result.

If you query the following,

var qry5 = “https://xxx.crm5.dynamics.com/api/data/v8.0/accounts?$count=true&$top=2″

You get

Querying data in Dynamics CRM 2016 using Web API

The total count is 19 even though the results requested were only top 2

Note, if there are more than 5000 records that the query returns, the count here would still return 5000 only.

Conclusion

The Web API query still has a few limitations and like the earlier ODATA v2 there are limitations on what kind of data can be queried. You can find the complete list here

In this post I have covered queries, in the later blogs hope to cover the other operations supported by WEB API.

Make your Dynamics CRM life easy with Inogic Dynamics CRM Solutions. Read more about our add-ons here.

Web API Actions in Dynamics CRM 2016

$
0
0

Taking forward our series on using WEB API in Microsoft Dynamics CRM 2016, we will now touch upon a feature that was not available in ODATA v2 of the earlier versions.

ODATA v2 only provided support for CRUD operations. But Dynamics CRM has some special messages/functions for special operations that are beyond the basic CRUD on an entity. To perform these actions in the earlier versions of Microsoft Dynamics CRM, we had to fall back on SOAP messages.

With Web API, actions are now supported. Action is equivalent to requests that are available in Dynamics CRM.

There are predefined Actions defined in Dynamics CRM 2016 that can be executed using Web API. Following is like where you will find the list of Web API actions. https://msdn.microsoft.com/en-in/library/mt607829.aspx

There are three types of Action as listed below.

  1. Unbound actions: It is not bound to any specific entity. i.e the first parameter to such actions does not include the entity. E.g. WinOpportunity, CancelContract etc
  2. Bound actions: It is bound to specific entity. i.e the first parameter to such actions does not include the entity. e.g. – AddToQueue Action
  3. Custom action: It is custom actions developed by developers using Processes.

We are explaining Web API Action called ConvertSalesOrderToInvoice which corresponds to the organization service ConvertSalesOrderToInvoiceRequest. ConvertSalesOrderToInvoice action is not bound to any entity and does not return a value. ConvertSalesOrderToInvoice Action require following parameters.

SalesOrderId: Guid of the order to convert. (This is compulsory parameter)

ColumnSet: List of attributes to retrieve from the created invoice. (This is compulsory parameter)

Below is the code that are used to execute ConvertSalesOrderToInvoice Action.

//This function is used execute the standard action of webAPI

Here is the main Ajax request that execute the Action.

function executeAction() {

    var saleOrderID = null;

    var columnsSet = null;

    try {      

        //set the param values

        saleOrderID = "D035DD97-3AB5-E511-80E2-6C3BE5A852B0"; 

        columnsSet = new Array("name", "totalamount");      

        //create the action object

        var actionObj = {

            "SalesOrderId": saleOrderID,

            "ColumnSet":

                {

'AllColumns': false,

                    'Columns': columnsSet

                },

        };

        // call this function to execute the action. Please note the () used along with the function name

        Inogic.ApiLib.execute(actionObj, "ConvertSalesOrderToInvoice()", function (data) {

            // open the Created invoice record

            Xrm.Utility.openEntityForm("invoice", data.invoiceid);           

        }, function (error) { throw new Error(error.message);

    } catch (e) {

        alert(e.message);

    }

}

//This function is used to execute the Web API Action

            execute: function (req, reqName, successCallback, errorCallback) {

                //create AJAX request

                $.ajax({

                    type: "POST",

                    contentType: "application/json; charset=utf-8",

                    datatype: "json",

                    url: encodeURI(this.getWebAPIPath() + reqName),

                    data: window.JSON.stringify(req),

                    beforeSend: function (xhr) {

                        //Specifying this header ensures that the results will be returned as JSON.            

                        xhr.setRequestHeader("Accept", "application/json");

                        xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");

                        xhr.setRequestHeader("OData-MaxVersion", "4.0");

                        xhr.setRequestHeader("OData-Version", "4.0");

                    },

                    success: function (data, textStatus, xhr) {

                        //successCallback function

                        successCallback(data);

                    },

                    error: function (xhr, textStatus, errorThrown) {

                        errorCallback(Inogic.ApiLib.errorHandler(xhr));

                    }});

            },

//This function is used to get the client URL

   getClientUrl: function () {

                //Get the organization URL

                if (typeof GetGlobalContext == "function" &&

                    typeof GetGlobalContext().getClientUrl == "function") {

                    return GetGlobalContext().getClientUrl();

                }               

            }

Similar to this you can execute any Web API actions that are listed and your custom action that you developed.

Conclusion:

Web API can be used for executing messages other than CRUD as well.

Everything in Maplytics – Dynamics CRM and Bing Maps integration is now a search away at our Maplytics InfoCentre.


Web API functions in Dynamics CRM 2016

$
0
0

The Web API which is introduced in Microsoft Dynamics CRM 2016 enhances the experience while developing through different programming languages, devices and platforms. It implements the OData, version 4.0, an OASIS standard which is used to build as well as to consume RESTful APIs over rich data sources.

There are predefined functions introduced in the Web API which when executed help you to retrieve data. They may have parameters and they may return values. Functions may be bound to a specific entity. You will find the list of Web API functions on the web page: https://msdn.microsoft.com/en-us/library/mt607866.aspx.

Let’s take an example of RetrieveVersion function

The RetrieveVersion function is used to get the version number of Microsoft Dynamics CRM Server. It is similar to the RetrieveVersionRequest which is used to get the version number through organization services.

The function is not bound to any entity types and does not require any parameters.

Here is the code for executing the standard functions of the WebAPI.

//This function is used execute the standard functions of webAPI

function exeFunction() {
    try {
        Inogic.ApiLib.executeFunction("RetrieveVersion()", exeFunctionSucess, function(error){throw new Error(error.message)};

    } catch (e) {
        showMessage(e.message);
    }
}

//success call back
function exeFunctionSucess(data) {
    try {

        var versionNumber = data;
    }
    catch (e) {
        showMessage(e.message);
    }
}

Here is the main code for executing the functions and fetching the results.

// This function is used to execute the function and get the results
 
            executeFunction: function (funName, successCallback, errorCallback) {

                //create the AJAX request
                $.ajax({
                    type: "GET",
                    contentType: "application/json; charset=utf-8",
                    datatype: "json",                  
                    url: encodeURI(this.getWebAPIPath() + funName),                   
                    beforeSend: function (xhr) {
                        
// This header ensures that the results will be returned as JSON.   
          
                        xhr.setRequestHeader("Accept", "application/json");                    
                     
//xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");

                        xhr.setRequestHeader("OData-MaxVersion", "4.0");
                        xhr.setRequestHeader("OData-Version", "4.0");
                    },
                    success: function (data, textStatus, xhr) {

                        //successCallback function - Here you get the version number.

                        successCallback(data.Version);
                    },
                    error: function (xhr, textStatus, errorThrown) {
                        errorCallback(Inogic.ApiLib.errorHandler(xhr));
                    }
                });

            }

Web API Query Functions:

Query functions are those which are used to add a filter criteria in Odata query. These functions accept parameters and return a Boolean value. It serves to be an additional filter applied on Odata query.

You would find predefined query functions of Web API in the following link. https://msdn.microsoft.com/en-us/library/mt607843.aspx

Let us consider ThisYear Function. It is used to retrieve data within the current year. It accepts parameter as property name (date attribute name) and returns data within this year.

Note: This function only accepts Date Datatype as a parameter. If you pass a parameter other than the date, then it throws an error.

// This function is used to execute the query function 

function executeQueryFunction() {

    var query = null;

    try {

        // create the query

        query = "?$select=accountcategorycode,accountnumber,creditonhold,createdon,numberofemployees,name,revenue";

        // add the query function
 
        query += "&$filter=Microsoft.Dynamics.CRM.ThisYear(PropertyName='modifiedon')";

        //query += "&$filter=Microsoft.Dynamics.CRM.Today(PropertyName='modifiedon')";

        //call this function to execute the query function
        Inogic.ApiLib.executeQueryFunction("accounts", query, executeQueryFunctionSuccess, executeQueryFunctionError, executeQueryFunctionError, false);

    } catch (e) {
        showMessage(e.message);
    }
}

//success call back

function executeQueryFunctionSuccess(data) {
    try {

        //This function is used to process return data

        processData(data);

        HideBusyIndicator();
    }
    catch (e) {
        showMessage(e.message);
    }
}

This is the main Ajax call function.

// This function is used to retrieve records using WebAPI query function

            executeQueryFunction: function (entitySetName, query, successCallback, errorCallback, onComplete) {

                try {
                
                    //create AJAX request

                    $.ajax({
                        type: "GET",
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        url: encodeURI(oDataUrl),
                        beforeSend: function (xhr) {
                           
//This header ensures that the results will be returned as JSON. 

                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");                          
                            xhr.setRequestHeader("Prefer", "odata.include-annotations=*");

                        },
                        success: function (data, textStatus, xhr) {
                            if (data != null) {
                                successCallback(data.value);                              
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(xhr.statusText);
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }

            },

When you execute the above query then it will return all Accounts which are modified during a particular year.

Before moving on to the next post, you may like to read about Dynamics CRM and Bing Maps integration.

Impersonation available using WEB API in Dynamics CRM 2016

$
0
0

Introduction:

Microsoft Dynamics CRM online 2016 update and Dynamics CRM 2016 (on-premises) has introduced a new concept called the Web API. This can be used across a wide variety of programming languages, platforms, and devices. One of the features of Web API is Impersonation.

Back in the days of CRM 4, Impersonation through scripting was supported by including the impersonation details in the header of the SOAP request.

Later this feature was removed and there was no way to impersonate a user through Scripting.

Impersonation is used when you want to execute business logic (code) on behalf of another CRM user. This is necessary because the CRM Web services can be called by various clients and services on behalf of a CRM user. Impersonation involves two different users where User (X) is used for executing the code to perform some tasks on behalf of another user (Y).

Walkthrough of Impersonation through Script

The User account (X) has to be given the prvActOnBehalfOfAnotherUser privilege to perform the task.

In order to impersonate a user through the Web API, you need to add ‘MSCRMCallerID’ key with GUID of the impersonated user. In the below example, a new contact entity is created on behalf of the user with systemuserid B65AB846-7EBE-E511-80DF-00155D06F307.

Here’s the code which helps you to impersonate a user through the Web API.

function impersonateUserReq()
{
    var userID = null;

    try {

        // create the contact object
        var contact = new Object();
        contact.firstname = "FirstName";
        contact.lastname = "LastName";
        contact.accountrolecode = 2;
        contact.creditonhold = false;
        contact["parentcustomerid_account@odata.bind"] = "/accounts(89C202DF-B1AF-E511-80E9-00155D06D000)"

        ///set the impersonateUser userid -  
        userID = "B65AB846-7EBE-E511-80DF-00155D06F307";

        Inogic.ApiLib.impersonateUser("contacts", contact, userID,
           impersonateUserSuccess,
           impersonateUserError);
    } catch (e) {
        showMessage(e.message);
    }
}
      // this Actual ajax request function is used to create the record and impersonate the user
            impersonateUser: function (entitySetName, entity,userId, successCallback, errorCallback) {

                var jsonEntity = null;

                try {

                    //create json object
                    var jsonEntity = window.JSON.stringify(entity);

                    //create AJAX request
                    $.ajax({
                        type: "POST",                      
                        contentType: "application/json; charset=utf-8",
                        datatype: "json",
                        url: encodeURI(this.getWebAPIPath() + entitySetName),
                        data: jsonEntity,
                        beforeSend: function (xhr) {
                            //Specifying this header ensures that the results will be returned as JSON.            
                        
                            xhr.setRequestHeader("MSCRMCallerID", userId);
                            xhr.setRequestHeader("Accept", "application/json");
                            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                            xhr.setRequestHeader("OData-MaxVersion", "4.0");
                            xhr.setRequestHeader("OData-Version", "4.0");
                        },
                        success: function (data, textStatus, xhr) {

                            //call successCallback
                            successCallback(xhr.getResponseHeader("OData-EntityId"));
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            errorCallback(Inogic.ApiLib.errorHandler(xhr));
                        }
                    });
                } catch (e) {
                    throw new Error(e);
                }
            },

In the above code, the only addition is the following line of code

   xhr.setRequestHeader("MSCRMCallerID", userId);

Once the callerid is set, the record is created using the privileges that is assigned to the user specified in the callerid rather than the logged in user.

Conclusion:

On a concluding note, impersonation helps to perform operations on behalf of other users if the system account running the code has the necessary privileges.

You may also like to read : Make your Dynamics CRM life easy with Inogic Dynamics CRM Solutions.

Executing Predefined Queries in Dynamics CRM using Web API through Scripts

$
0
0

Introduction:

What do you mean by Predefined Query?

System Views created in the CRM contains an inbuilt query which displays the results satisfying the Query mentioned in the view.

For e.g. “Active Contacts” an OOB system view.

Also, Users can create their views in Advance Find by specifying their criteria’s and save it giving any custom name.

These queries are known as Predefined Queries.

Using Web API we can retrieve and execute these Predefined Queries in the below way:

First in order to execute the Query we require the Query ID which we can retrieve in below manner:

There are be 2 types of Query in general:

  1. SavedQuery: Contains the SystemDefined View for an Entity. These views are stored in SavedQuery entity.
  1. UserQuery: Contains the Advanced Find Views created by the user for an Entity. These

Views are stored in UserQuery Entity.

To get the Query ID of System View the syntax is as shown below:

If it is System View then it is:

GET [Organization URI]/api/data/v8.0/savedqueries?$select=name,savedqueryid&$filter=name eq ‘Active Contacts’

If it is Custom View (User created view) then it is:

GET [Organization URI]/api/data/v8.0/userqueries?$select=name,userqueryid&$filter=name eq Custom Filter View’

Where

GET [Organization URI]: https://myorg.crm.dynamics.com [CRM Server Url]

Code to get the Query Id Variable:

//Method to retrieve the Query Id 
function retrieveQueryId(viewName, queryEntity, selectOptions) {
    var functionName = "retrieveQueryId";
    var viewId = "";
    try {
        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()
        //To Retrieve PreDefinedQuery Query
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + queryEntity + "?" + selectOptions + "&$filter=name eq '" + viewName + "'"), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();

        if (req.status == 200) {

            var data = JSON.parse(req.response);
            var dat = data.value;
            //If record greater than 0 i.e. atleast 1 record found
            if (dat.length > 0) {
                //If it is System View
                if (queryEntity.toLowerCase() == "savedqueries") {
                    //read the first record
                    viewId = dat[0].savedqueryid;
                }//If it ia an User Query [Advanced Find]
                else if (queryEntity.toLowerCase() == "userqueries") {
                    //Read the first record
                    viewId = dat[0].userqueryid;
                }
            }


        }
        else {
            var error = JSON.parse(req.response).error;

        }

        return viewId;
    } catch (e) {
        alert(e.message);
    }
}

Where

  • viewName = View Name For e.g. “Active Contacts”
  • queryEntity = If it is System View then it is “savedqueries”. For Custom View it is “userqueries”
  • selectOptions = Columns which you want to select For e.g. “select=name,savedqueryid” for System View & “select=name,userqueryid

This functions returns the viewId of the Query record.

Now, we will see how to execute this Query after getting the ViewId:

Syntax:

If it is System View then it is:

GET [Organization URI]/api/data/v8.0/contacts?savedQuery=00000000-0000-0000-00aa-000010001002

If it is Custom View (User created view) then it is:

GET [Organization URI]/api/data/v8.0/contacts?userQuery=77444281-0010-1300-00aa-000010001002

Code to Execute the Query:

//Method executes the Query and returns Array of Records
function executeQuery(entityName, queryType, viewid) {
    var functionName = "executeQuery";
    var recordsFromView = null;
    try {

        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()

        if (viewid == "") {
            return;
        }
        //Sync Operation
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + entityName + "?" + queryType + "=" + viewid), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();
        //If it is executed successfully
        if (req.status == 200) {

            var data = JSON.parse(req.response);
            recordsFromView = data.value;

        }
        else {
            var error = JSON.parse(req.response).error;
        }

        return recordsFromView;

    } catch (e) {
        alert(e.message);
    }
}

Where

  • clientUrl = CRM Server Url
  • entityName = The Entity whose View Id we have found
  • queryType = If it is a System View then queryType = “savedQuery”, For Custom View (user created) it is “userQuery”
  • viewid: ViewId which we retrieved above using retrieveQueryId() method.

Also, we can filter a particular View records based on its parent record.

For e.g.: There is System view “Open Opportunities”. We will filter the records based on a particular Account and retrieve the Open Opportunities related to this record.

Let’s see How we can achieve this below:

  1. Get the “Open Opportunities” view Id using retrieveQueryId() method which is shown above.
  2. After that call this function:

//Method to return records from View by Filtering it out based on the Parent Record
function executeFilterQuery(filterentityName, filterentityId, relationshipName,queryType, viewId) {
    var functionName = "executeQuery";
    var recordsFromView = null;
    try {

        //Get Client Url
        var clientUrl = Xrm.Page.context.getClientUrl();
        //Declare new XML HttpRequest Object
        var req = new XMLHttpRequest()

        if (viewId == "") {
            return;
        }
        //Sync Operation
        req.open("GET", encodeURI(clientUrl + "/api/data/v8.0/" + filterentityName + "(" + filterentityId + ")/" + relationshipName + "/?" + queryType + "=" + viewId), false);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.send();
        //If it is executed successfully
        if (req.status == 200) {

            var data = JSON.parse(req.response);
            recordsFromView = data.value;

        }
        else {
            var error = JSON.parse(req.response).error;
        }

        return recordsFromView;

    } catch (e) {
        alert(e.message);
    }
}

Where:

  • filterentityName: Parent record by which we need to filter the records. For e.g. Accounts in our case.
  • filterentityId: Parent Record Id
  • relationshipName: It is the collection-valued navigation property name. In our case “opportunity_parent_account”
  • queryType = If it is a System View then queryType = “savedQuery”, For Custom View (user created) it is “userQuery”
  • viewid: ViewId which we retrieved above using retrieveQueryId() method.

For Testing purpose you may call the below method on any event of the form:

//Method called on Load event
function startOperation() {

    //For System Views
    //Retrieve the View Id for the system view "Active Contacts"
    var systemQueryId = retrieveQueryId("Active Contacts", "savedqueries", "$select=name,savedqueryid")
    var queryRecords = executeQuery("contacts", "savedQuery", systemQueryId);

    //For User Created Views
    //Retrieve the View Id for the user created view "User Created Custom View"
    var customQueryId = retrieveQueryId("User Created Custom View", "userqueries", "$select=name,userqueryid")
    var customQueryRecords = executeQuery("contacts", "userQuery", customQueryId);


    //To Execute Views By filtering it based on parent record

    //Retrieve the View Id for the system view "Active Contacts"
    var filterviewId = retrieveQueryId("Open Opportunities", "savedqueries", "$select=name,savedqueryid");

    //Retrieve the Opportunities record that belong to particular Account
    var oppRecords = executeFilterQuery("accounts", "D8747EC1-A6F5-E511-80E2-C4346BAC339C", "opportunity_parent_account","savedQuery", filterviewId);

}

 Conclusion:

In this way we can execute Predefined Queries using Web API through Scripts.

Lets have a quick glimpse of new exciting features coming up in Maplytics May Release.

Execute Web API request using Angular JS in Dynamics CRM

$
0
0

Introduction

In our earlier blogs of  Web API introduced in Dynamics CRM 2016, we have explained different requests and functions of Web API to querying and performing operations in Dynamics CRM.

This blog will show you how to execute Web API request using Angular JS.

This article would be helpful for those who have knowledge of Angular JS and now want to know how to use Angular JS to perform operations in Dynamic CRM.

Angular JS provides in-built service “$http” that facilitates communication with the remote HTTP servers via XMLHttpRequest object or via JSONP. In JQuery, $.ajax is used for same purpose.

So, we can use “$http” service to execute Web API request.

Below is the code snippet that executes Web API function:

$http({
                url: encodeURI(Xrm.Page.context.getClientUrl() + "/api/data/v8.0/RetrieveVersion()"),
                dataType: 'json',
                method: 'GET',
                headers: {
                    "Content-Type": "application/json"
                }
            }).success(function (response) {
                successCallback(response.Version);
            })
        .error(function (error) {
            errorCallback(error);
        });

You can see that, we pass Web API request to retrieve version of Dynamics CRM to URL. Execute “RetrieveVersion()” function, similarly you can execute other Web API functions like “WhoAmI()”, ”GetDefaultPriceLevelRequest()”, etc.

Below is the code snippet that query Dynamics CRM data,

$http({
                url: encodeURI(Xrm.Page.context.getClientUrl() + "/api/data/v8.0/accounts?$select=name&$top=3"),
                dataType: 'json',
                method: 'GET',
                headers: {
                    "Accept": "application/json",
                    "OData-MaxVersion": "4.0",
                    "OData-Version": "4.0",
                    "Prefer": "odata.maxpagesize=3"
                }
            }).success(function (response) {
                successCallback(response);
            })
       .error(function (error) {
           errorCallback(error);
       });

In this code, we have passed Web API query to select top 3 accounts. Here, the only difference between above code and the code that executes Web API function is URL and headers.

Conclusion:

If you are developing an application for Dynamics CRM using Angular JS, we can use $http service to get Dynamics CRM data or perform operations in Dynamics CRM.

Completed  with Dynamics CRM implementation? Whats next? Monitor User Adoption!

Execute Action with “EntityCollection” Parameter using Web API in Dynamics 365

$
0
0

Introduction

Recently, we had a requirement where we wanted to Execute Custom Action in Dynamics CRM by passing “EntityCollection” type parameter using Web API. We have discussed how to execute the action using Web API in one of our earlier blog. However, in this blog we just explained executing action with string parameter.

Here we are going to focus on executing action with “EntityCollection” parameter using Web API.

You can see below that we have created a Custom Action:

Dynamics CRM Web API

Below code snippet will help you to Execute Action using Web API:

function CallCustomActionWithEntityCollectionParameter() {
    try {

        var reqName = "new_Approve";
        var clientUrl = Xrm.Page.context.getClientUrl();
        var parameters = {
           "Accounts"://EntityCollection parameter
             [
                  {
                      "@odata.type": "Microsoft.Dynamics.CRM.account",//entity type
                      "accountid": "C4CA0B66-59B9-E611-8106-C4346BDC0E01",//Record's guid
                      "name": "Test",//name field of the account entity
                      "accountnumber": "123"//accountnumber field of the account entity
                  },
                  {
                      "@odata.type": "Microsoft.Dynamics.CRM.account",
                      "accountid": "CD67D78E-16BB-E611-8109-C4346BDC3C21",
                      "name": "Test2",
                      "accountnumber": "1234"
                  }
             ]
        };

        //Create request
        var req = new XMLHttpRequest();
        req.open("POST", clientUrl + "/api/data/v8.2/" + reqName, true);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");

        req.onreadystatechange = function () {

            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;

                if (this.status == 200 || this.status == 204) {
                    //success callback   
                    console.log("Success");
                } else {
                    //error callback      
                    console.log("Error");
                }
            }
        };
        req.send(JSON.stringify(parameters));

    } catch (e) {
        alert(e.message);
    }
}

Conclusion:

This blog will help you to execute action by passing “EntityCollection” parameter using Web API in Dynamics 365.

Now export Dynamics 365 reports to multiple formats in mere one click using Click2Export!

Retrieve Metadata using Name in Web API

$
0
0

Dynamics 365 introduced a lot of new features and improvements over the previous versions to offer more control and functionalities to the user. The ability to retrieve metadata using name is one such improvement in Web API.

Previously, to retrieve entity metadata, users needed to use ‘metadataid’. With the addition of this improvement, users can now retrieve the Entity/Attributes/Global Option Set meta by using the logical name.

When do we need to retrieve metadata?

There are many scenarios where the user needs object type code, primary attributes, localized label, list of entity attributes, etc. or when the user wants option set metadata. In such situations the user needs to read the entity metadata which can now be easily retrieved.

Let us see an example to understand how to retrieve Entity metadata:

  • To retrieve Contact entity metadata using Name, use the script mentioned below;

//this function is used to retrieve entityMetadata
function retrieveEntityMetaData() {

    var entityName = "";
    try {       
        //set variable value
        entityName = "contact";

        //create AJAX request
        $.ajax({
            type: "GET",
            contentType: "application/json; charset=utf-8",
            datatype: "json",
            url: encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')"),

            beforeSend: function (xhr) {
                //Specifying this header ensures that the results will be returned as JSON.             
                xhr.setRequestHeader("Accept", "application/json");
                xhr.setRequestHeader("Accept", "application/json");
                xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                xhr.setRequestHeader("OData-MaxVersion", "4.0");
                xhr.setRequestHeader("OData-Version", "4.0");
            },
            success: function (data, textStatus, xhr) {
                //Call successCallback
                retrieveEntityMetaDataSuccess(data);
            },
            error: function (xhr, textStatus, errorThrown) {
                errorCallback(xhr);
            }
        });

    } catch (e) {
        showMessage(e.message);
    }
}

  •  The ‘success callback’ function mentioned below will get the metadata;

//success call back
function retrieveEntityMetaDataSuccess(data) {
    try {

        if(data != null) {

            //get objectTypeCode
            var objectTypeCode = data.ObjectTypeCode;

            //get primary name
            var primaryAttribute = data.PrimaryNameAttribute;
        }
    }
    catch(e) {
        showMessage(e.message);
    }
}

  •  If you want to retrieve metadata of any particular attribute then pass the following in url parameter in Ajax request;

url:encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')/Attributes(LogicalName='parentcustomerid')") ,
success: function (data, textStatus, xhr) {
                        //Call successCallback
                        successCallback(data);
                    },

 In successCallback function, use data.value to get the attribute metadata.

  • If you want to retrieve all the entity attributes then pass the following in url parameter in Ajax request;

url:encodeURI(this.getWebAPIPath() + "EntityDefinitions(LogicalName='" + entityName + "')/Attributes")

 In successCallback function, use data.value to get the list of entity attributes.

  • If you want to retrieve relationship metadata then you can use the following in url parameter in Ajax request;

url: encodeURI(this.getWebAPIPath() + "RelationshipDefinitions(SchemaName='account_primary_contact')")

 In successCallback function, use data.value to get the relationship metadata.

  • If you want to retrieve Global option set metadata then use the following in url parameter in Ajax request;

url: encodeURI(this.getWebAPIPath() + "GlobalOptionSetDefinitions(Name='budgetstatus')")

In successCallback function, use data.Options to get all options.

 

Conclusion:

Now with the addition of the ability to retrieve metadata using name in Dynamics 365, users can easily retrieve metadata.

Boost your productivity with Inogic Apps for Dynamics 365 on Microsoft AppSource – Try today!

Use WEB API Batch Request in Dynamics 365 to execute long FetchXML

$
0
0

Introduction:

Recently we had a project where we use WEB API for retrieve the records from Dynamics CRM. In our project, we dynamically create FetchXML to retrieve records but sometimes Fetchxml have a lot of columns and conditions etc so its length get increase and we this the fetchxml in URL which violates the browser URL length rule. So When we try to execute this long length FetchXML and retrieve the records using the GET method, We were getting the error message of “HTTP Error 404 – Not Found” because of WEB API request fails to execute too long FetchXML. When we work on this error message, we find that we need to use WEB API Batch Request to execute the long FetchXML.

In the below example, we execute the long FetchXML of account entity and use POST request to execute long FetchXML.

First, we created the simple request body as below:

//create request body
var bodyFetch='';
bodyFetch = '--batch_recordfetch\n'
bodyFetch += 'Content-Type: application/http\n'
bodyFetch += 'Content-Transfer-Encoding: binary\n'
bodyFetch += '\n'
bodyFetch += 'GET [CRM URL]/api/data/v8.2/accounts?fetchXml=' + fetch + ' HTTP/1.1\n'
bodyFetch += 'Content-Type: application/json\n'
bodyFetch += 'OData-Version: 4.0\n'
bodyFetch += 'OData-MaxVersion: 4.0\n'
bodyFetch += 'Prefer: odata.include-annotations=*\n'
bodyFetch += '\n'
bodyFetch += '--batch_recordfetch--'

Note: ‘fetch’ is the parameter of the long FetchXML.

And we pass the created the simple request body as data to Ajax request and we will receive the response of request as success or failure as below:

//create AJAX request
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
datatype: "json",
async: true,
url: '[CRM URL]/api/data/v8.2/' + '$batch',
data: bodyFetch,
beforeSend: function (xhr) {
//Specifying this header ensures that the results will be returned as JSON.
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("OData-MaxVersion", "4.0");
xhr.setRequestHeader("OData-Version", "4.0");
xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
xhr.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_recordfetch");
},
//success callback
success: function (data, textStatus, xhr) {
data = JSON.parse(data.substring(data.indexOf('{'), data.lastIndexOf('}') + 1));
if (data != null) {
if (data.value == null) {
alert("success");
}
}
},
//error callback
error: function (xhr, textStatus, errorThrown) {
alert("failed");                          
}
});

Conclusion:

User can easily execute the long length FetchXML using the WEB API Batch Request.

To read more about FetchXML visit here.

Export Dynamics CRM Reports


Execute a workflow using Xrm.WebApi.online.execute method via JavaScript in Dynamics 365 CRM v9

$
0
0

Introduction

In this blog, we are going to create a request using ExecuteWorkflow action and would execute the request that would execute a custom workflow. This approach would eliminate the need to create an Ajax request and is supported across web client, UCI and Mobile.

For demonstration purpose, we have created a custom workflow. This would create a task in our CRM related to the current account when it’s triggered by a JavaScript function.

Note: Make sure to keep your existing custom workflow available to run as an on-demand process.

JavaScript in Dynamics 365 CRM v9

Now with the help of execute request we are going to trigger that workflow.

Solution: Following is the piece of code to achieve the above objective.

javascript

In the above piece of code, we have created a dynamics request object named “ExecuteCustomWorkflowRequest” and we have passed current account id to it along with workflow id. We would recommend to retrieve workflow id dynamically. As of now, we have passed hard coded workflow id for demonstration purpose, which can be found in the URL of workflow as highlighted in blue colour in the following screenshot:

JavaScript in Dynamics 365 CRM v9

Once the “triggerCustomWorkflowRequest” request is built, we would pass it to execute method which would then invoke “ExecuteWorkflow” action. This action will execute our workflow to create task related to the account record whose id was passed in the “triggerCustomWorkflowRequest” request.

Upon execution of our custom workflow via execute method, following task is created.

JavaScript in Dynamics 365 CRM v9

Also, following is a link to execute workflow via HTTP Request: https://www.inogic.com/blog/2016/11/execute-workflow-using-web-api-in-dynamics-365-2/

For more information on execute method visit the following link: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/online/execute

You can find complete list of WebApi actions here:  https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/actions?view=dynamics-ce-odata-9

Hope it helps.

Execute Action with ColumnSet(ComplexType) type parameter Using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0

$
0
0

Introduction

Microsoft has introduced Xrm.WebApi.online.execute to execute an action in Dynamics CRM version 9.0. In our last blog we have seen how to Execute action using Xrm.WebApi.online.execute in Dynamics CRM. In this blog we will see how to execute action with “ColumnSet(ComplexType)” type property.

Here we are executing “GenerateQuoteFromOpportunity” action for sample purpose as this action contains the “ColumnSet(ComplexType)” type parameter.

Properties of ColumnSet(ComplexType) parameter:

xrm

For these properties we need to add another getMetadata method as shown in the below example.

Syntax:

Xrm.WebApi.online.execute(request).then(successCallback, errorCallback);

successCallback: This function call is for when is action executed successfully.

errorCallback: This function call is for when there is any error while executing action. It returns an error as result in string format.

Given below is the example of how to write the function to execute “GenerateQuoteFromOpportunity” action:

Generate Parameters:

/**

* This function generates quote from opportunity using GenerateQuoteFromOpportunity action

* @param formContext

* @param opportunityID

*/

function executeAction(executionContext) {

let functionName = “executeAction”;

var opportunityID = null;

var formContext = null;

try {

debugger;

//Get form context

formContext = executionContext.getFormContext();

//Get opportunity id

opportunityID = !isValid(executionContext.getFormContext().data)

|| !isValid(executionContext.getFormContext().data.entity)

|| !isValid(executionContext.getFormContext().data.entity.getId)

? null : executionContext.getFormContext().data.entity.getId();

//Set parameters

var GenerateQuoteFromOpportunityReq = function (OpportunityId, ColumnSetVal) {

this.OpportunityId = { “guid”: OpportunityId };

this.ColumnSet = {

“AllColumns”: ColumnSetVal,

“getMetadata”: function () {

return {

boundParameter: null,

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”,

parameterTypes: {

“AllColumns”: {

“typeName”: “Edm.Boolean”, //Primitive Type

“structuralProperty”: 1

}

}

}

}

};

this.getMetadata = function () {

return {

boundParameter: null,

parameterTypes: {

“OpportunityId”: {

“typeName”: “Edm.Guid”, //Primitive Type

“structuralProperty”: 1

},

“ColumnSet”: {

“typeName”: “mscrm.ColumnSet”, //Complex Type

“structuralProperty”: 2

}

},

operationType: 0,

operationName: “GenerateQuoteFromOpportunity”

};

};

};

var generateQuoteFromOpportunityReq = new GenerateQuoteFromOpportunityReq(opportunityID, true);

}

Execute Action:

Xrm.WebApi.online.execute(generateQuoteFromOpportunityReq).then(function (result) {

//Validate result

if (!isValid(result) || !isValid(result[“responseText”])) {

return;

}

else {

//get result in JSON object

var resultJson = JSON.parse(result[“responseText”]);

//Validate JSON

if (isValid(resultJson)) {

//Validating the attributes

if (!isValid(Xrm) || !isValid(Xrm.Navigation)) { return; }

//openAlertDialog

Xrm.Navigation.openAlertDialog({ confirmButtonLabel: “Ok”, text: “Quote with ID: ” + resultJson.quoteid + ” is generated successfully. ” });

}

}

}, function (error) {

throwError(functionName, error);

});

} catch (error) {

throwError(functionName, error);

}

}

On success it returns a promise object with specific attributes.

In above example we have used ‘AllColums’ property of “ColumnSet(ComplexType)” parameter. In the same way we can use ‘Columns’ parameter. We just need to set “Edm.String” as typename in getMetadata method.

Conclusion

In this blog, we have seen how we can execute action with “ColumnSet(ComplexType)” type parameter using Xrm.WebApi.online.execute in Dynamics 365 CRM V9.0.

Click2Clone-One-Click-Productivity-App-to-Copy_clone-Dynamics-365_CRM-Records

How to Perform Basic CRUD Operations using Offline Web API in Mobile Clients

$
0
0

Dynamics 356

Introduction

Microsoft has provided offline ability to use “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”. Mobile Offline allows users to work with the data in offline mode as well i.e. when they are not connected to the internet. So, in the offline mode, if we want to create or manage the data programmatically, we need to use Microsoft Dynamics Offline Web API methods within the script.

Microsoft Dynamics Offline Web API methods can be used for basic commands while working in offline mode. The basic methods that are available for using the Xrm.WebApi.offline include the following: createRecord,  retrieveRecords, retrieveMultipleRecords, updateRecord and deleteRecord.

Note: These OfflineWebApi methods will work only for tables that are enabled for mobile offline and only basic validation will be performed on the data that is being input.

By using the below method, we can identify whether the entity is available to use in offline mode: Xrm.WebApi.offline.isAvailableOffline(entityLogicalName);

In this blog, I will show the sample codes to create, retrieve, update and delete records using Xrm.WebApi.offline methods in JavaScript.

  1. Create:

It is used to create table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. data – JSON object of the data to create a new record.

//This function is used to create a contact record
function createContact() {
    var objContact = null;
    try {
          //Create the Json object of contact record
          objContact = new Object();
          objContact["firstname"] = "Jenny";
          objContact["lastname"] = "Smith";
          //Call Create method
          Xrm.WebApi.offline.createRecord("contact", objContact).then(function (result) {
              Xrm.Navigation.openAlertDialog("Contact record has been created successfully.");
          },
        function (error) {
            Xrm.Navigation.openAlertDialog(error.message);
        });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. Update:

It is used to update table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.
    3. data – JSON object of the data to update record.

//This function is used to update a contact record
function updateContact() {
    var objContact = null;
    try {
        //Create the Json object of contact record
        objContact = new Object();
        objContact["telephone1"] = "18018015012";
        objContact["fax"] = "123456";
        objContact["parentcustomerid_account@odata.bind"] = "/accounts(08f4aca2-9793-eb11-b1ac-0022481cb79b)"
        //Call Update method
        Xrm.WebApi.offline.updateRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", objContact).then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been updated successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Delete:

It is used to delete table record. The required parameters of this function are;

    1. entityLogicalName – Logical name of the table.
    2. entityId – GUID of record.

//This function is used to delete a contact record
function deleteContact() {
    try {
        //Call Delete method
        Xrm.WebApi.offline.deleteRecord("contact", "5d0111d1-bf05-4079-b695-247e4c9acac2").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact record has been deleted successfully.");
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

  1. Retrieve:

It is used to retrieve a single record from a table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. entityId – GUID of record.
  3. options – OData Query.

//This function is used to retrieve single contact record
function retrieveContact() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveRecord("contact", "fb4231a9-dba4-eb11-b1ac-000d3a4e57c1", "?$select=firstname,lastname,telephone1").then(function (result) {
            Xrm.Navigation.openAlertDialog("Contact retrieved successfully - FirstName: " + result.firstname + ", LastName: " + result.lastname + " and Telephone: " + result.telephone1);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }

  1. RetrieveMultiple:

It is used to retrieve multiple records from the table. The required parameters of this function are;

  1. entityLogicalName – Logical name of the table.
  2. options – we can use OData Query and FetchXML as well.

RetrieveMultiple method with OData Query

//This function is used to retrieve contact records using OData Query
function retrieveContactsWithOdata() {
    try {
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?$select=firstname,lastname,telephone1&$filter=_parentcustomerid_value ne null").then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

RetrieveMultiple method with FetchXML – To use a FetchXML, use the fetchXml attribute to specify the query.

//This function is used to retrieve contact records using Fetch XML
function retrieveContactsWithFetch() {
    var fetchXML = null;
    try {
        //Fetch XML to retrieve Contact records
        fetchXML = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
        "<entity name='contact'>" +
          "<attribute name='fullname' />" +
          "<attribute name='telephone1' />" +
          "<attribute name='contactid' />" +
          "<order attribute='fullname' descending='false' />" +
          "<filter type='and'>" +
            "<condition attribute='parentcustomerid' operator='not-null' />" +
          "</filter>" +
        "</entity>" +
      "</fetch>";
        //Call Retrieve method
        Xrm.WebApi.offline.retrieveMultipleRecords("contact", "?fetchXml=" + fetchXML).then(function (result) {
            Xrm.Navigation.openAlertDialog("Length: " + result.entities.length);
        },
      function (error) {
          Xrm.Navigation.openAlertDialog(error.message);
      });
    } catch (e) {
        Xrm.Navigation.openAlertDialog(e.message);
    }
}

Conclusion

By using the Offline Web API methods, we can easily create and manage the table record which is available in the offline database for offline use within mobile clients i.e., “Dynamics 365 for phones app” or “Field Service (Dynamics 365) App”.

Maplytics

 

Execute Different Web API Operations using PowerApps Portals (Preview)

$
0
0

Introduction

In the recent release, Microsoft has provided the ability using which we can perform different CRUD operations using Portals WEB API. The operations will run at server-side and are similar to Dynamics Web API Operations but the difference is in the way it is written and called in PowerApps Portals.

If you have a custom web page with a page template or web template and you want data displayed in the custom web page to be stored in Dynamics by performing some business logic then you need to use PowerApps Portals API, which will communicate with the Dynamics 365 in the backend and perform the required operation in Dynamics 365.

Let us consider a requirement where we need to record our punch in details, punch out details and if there is any incorrect entry then we need to delete that punch details. For this scenario, we will use PowerApps Portals Web API and see how we can implement the requirement.

So we will execute below four operations,

– Retrieve record
– Create record
– Update record
– Delete record

Before going directly to Web API, we need to first look at what are the configurations we need to do to allow Web API operations in PowerApps Portals.

Please check the below screenshots of the Portal Site Settings to allow Web API Operations in PowerApps Portal.

1. Create Site Setting in PowerApps Portal as below:

a. Enable the entity in PowerApps Portals

Note: new_logindetail is the logical name of the custom entity.

Execute Different WebAPI Operations using PowerApps Portals
b. Enable fields for API Operations

Execute Different WebAPI Operations using PowerApps Portals
c. Show Web API Errors in Portal

Execute Different WebAPI Operations using PowerApps Portals

Note: You need to create a Site Setting for each entity that needs to be enabled for Web API and if you want to enable all fields for Web API operations then you can use “*” or else you can specify the logical name of each field separated by a comma.

2. Create Entity Permission and Create new web role for Web API
You can navigate to Entity Permission entity directly from the navigation pane.

Execute Different WebAPI Operations using PowerApps Portals
Note: The highlighted is the custom entity used for performing Web API Operations. You can select any other entity which you want and give the privileges as shown above for the new Web Role which we will use for performing Web API Operations.

Execute Different WebAPI Operations using PowerApps Portals
Note: You can give any name to the Web Role but make sure to set Authenticated Users Role to Yes. By doing this only portal users i.e. authenticated users will able to perform Portal Web API CRUD Operations.

After our configurations are done, now we will see how we can perform different Web API operations in PowerApps Portal.

For executing Web API, Microsoft has provided a Wrapper AJAX function which we can use for executing any Web API method for any entity. Please check the below link to get and use the Wrapper AJAX function in your code.

https://docs.microsoft.com/en-us/powerapps/maker/portals/web-api-perform-operations#wrapper-ajax-function

As this is a common function which we can use for any Web API operations in the portal, so I will create a new Web Template and simply copy-paste the function code in the created Web Template as below:

AJAX Function Code Snippet:

<script>
(function(webapi, $){
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();

shell.getTokenDeferred().done(function (token) {
// add headers for AJAX
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
“__RequestVerificationToken”: token
}
});
} else {
ajaxOptions.headers[“__RequestVerificationToken”] = token;
}
$.ajax(ajaxOptions)
.done(function(data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject); //AJAX
}).fail(function () {
deferredAjax.rejectWith(this, arguments); // on token failure pass the token AJAX and args
});

return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)
</script>

So our Wrapper AJAX template will look as seen from the below screenshot

Execute Different WebAPI Operations using PowerApps Portals

Now, whenever we want to refer to this in any other Web Template, you just need to use the below line of code:
{% include ‘Wrapper AJAX Template’ %}

Note that here I have used my newly created Web Template name i.e. ‘Wrapper Ajax Template’.

Now let us create a new page, which will be visible when the user login the portal and allows the user to punch in from the portal. Remember in the web page we will just add an HTML page using a Page template using which the user can do Punch In. Following are the details of the web page created.

Execute Different WebAPI Operations using PowerApps Portals

In order to render HTML in Web Page, I have use Web Template but you can also use Content Page of Web Page to add your custom HTML in the Web Page. I will perform all CRUD operations in the Web Template. Now let’s understand that in step by step.

1. There is a custom entity created in Dynamics to store the Login/Logout Details in CRM. First, we will retrieve Punch In details created today and if Punch In the record found then we will display that in the table in HTML.

2. We will have 3 buttons “Punch In”, “Punch Out” and “Delete” to perform the respective operations using Portals Web API.

Our final HTML will look like below,

Execute Different WebAPI Operations using PowerApps Portals

To retrieve the data from CRM, we can use normal FetchXml and display data in HTML table by looping through each punch in record if record exist already. Below is the code to retrieve and the data and display it in the HTML Table.

{% fetchxml punchdetails %}
<fetch version=”1.0″ output-format=”xml-platform” mapping=”logical” distinct=”false”>
<entity name=”new_logindetail”>
<attribute name=”new_logindetailid” />
<attribute name=”new_logouttime” />
<attribute name=”new_logintime” />
<attribute name=”createdon” />
<order attribute=”createdon” descending=”false” />
<filter type=”and”>
<condition attribute=”createdon” operator=”today” />
</filter>
</entity>
</fetch>
{% endfetchxml %}

<table>
<tr><th>Login Time</th><th>Logout Time</th><th>Date Created</th><th>Actions</th>
{% for item in punchdetails.results.entities %}
<tr>
<td>{{item.new_logintime}}</td>
<td>{{item.new_logouttime}}</td>
<td>{{item.createdon}}</td>
<td>
<button type=”button” id=”delete” onclick=”deletePunchDetails(‘{{item.new_logindetailid}}’)”>Delete</button>
<button type=”button” id=”punch_out” onclick=”updatePunchDetails(‘{{item.new_logindetailid}}’)”>Punch Out</button>
</td>
</tr>
{% endfor -%}
<tr>
<td><button type=”button” id=”punch_in” onclick=”addPunchDetails()”>Punch In</button></td>
</tr>
</table>

Below is the screenshot of the how web template will look like after adding the code. In the same way, you need to add the code in the Web Template.

Please note “punchdetails” is the name of the fetchXml variable which we need to use to retrieve the results from fetchXml. Also, to update and delete specific entry we need to add Update and Delete buttons in each row dynamically and call the respective function by passing GUID of the record.

We don’t need to add Punch In in each row as Punch In button is used to create a new record of Login/Logout Details in CRM.

Now we will see the code for each of the Web API request.

1. Create Punch In record:

function addPunchDetails()
{
webapi.safeAjax({
type: “POST”,
url: “/_api/new_logindetails”,
contentType: “application/json”,
data: JSON.stringify({
“new_logintime”: new Date(), //Date Time
“new_name”: “Login_”+new Date().toLocaleDateString(), //String
“new_loginattempts”:1, //Whole Number
“new_usertype”:2 //Option Set
“new_user@odata.bind”:”/contacts({{user.Id}})”, //Setting Logged In User(Lookup)
“new_workingday”: “2,3,4” //Multi-Select Option Set
}),
success: function (res, status, xhr) {
}
});
}

When webapi.safeAjax is executed, it calls the AJAX Wrapper class which we already added in another web template and references it in this web template.

Also, fields which I used for create request are based on my requirement but you can use different fields with different data type as well.

2. Update or Punch Out:

function updatePunchDetails(id)
{
webapi.safeAjax({
type: “PATCH”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
data: JSON.stringify({
“new_logouttime”: new Date()
}),
success: function (res) {
console.log(res);
}
});
}

The id parameter which we pass to this method is the GUID of the record that we pass from the loop above. Similarly, we will have to pass the parameter to DELETE method as well as below:

3. Delete Punch entry from CRM

function deletePunchDetails(id)
{
webapi.safeAjax({
type: “DELETE”,
url: “/_api/new_logindetails(“+id+”)”,
contentType: “application/json”,
success: function (res) {
console.log(res);
}
});
}

Note: Also, when you create record from portal “System” will be set as the Owner of the record.

Records created in CRM:

Execute Different Web API Operations using PowerApps Portals

Also as mentioned above, if the user don’t have permission to access page or anonymous users will not be able to see the page and hence won’t be able to perform Web API Operations as seen from the below screenshot.

For Anonymous Users:

Execute Different Web API Operations using PowerApps Portals

Note: All PowerApps Portal Web API Operations follow OData query syntax and work in the same manner as our Dynamics OData query works.

Conclusion

In this way, you can execute different Web API operations as per your requirement from PowerApps Portals.

Use WEB API Batch Request in Dynamics 365 to execute long FetchXML

$
0
0

Introduction:

Recently we had a project where we use WEB API for retrieve the records from Dynamics CRM. In our project, we dynamically create FetchXML to retrieve records but sometimes Fetchxml have a lot of columns and conditions etc so its length get increase and we this the fetchxml in URL which violates the browser URL length rule. So When we try to execute this long length FetchXML and retrieve the records using the GET method, We were getting the error message of “HTTP Error 404 – Not Found” because of WEB API request fails to execute too long FetchXML. When we work on this error message, we find that we need to use WEB API Batch Request to execute the long FetchXML.

In the below example, we execute the long FetchXML of account entity and use POST request to execute long FetchXML.

First, we created the simple request body as below:

//create request body
var bodyFetch='';
bodyFetch = '--batch_recordfetch\n'
bodyFetch += 'Content-Type: application/http\n'
bodyFetch += 'Content-Transfer-Encoding: binary\n'
bodyFetch += '\n'
bodyFetch += 'GET [CRM URL]/api/data/v8.2/accounts?fetchXml=' + fetch + ' HTTP/1.1\n'
bodyFetch += 'Content-Type: application/json\n'
bodyFetch += 'OData-Version: 4.0\n'
bodyFetch += 'OData-MaxVersion: 4.0\n'
bodyFetch += 'Prefer: odata.include-annotations=*\n'
bodyFetch += '\n'
bodyFetch += '--batch_recordfetch--'

Note: ‘fetch’ is the parameter of the long FetchXML.

And we pass the created the simple request body as data to Ajax request and we will receive the response of request as success or failure as below:

//create AJAX request
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
datatype: "json",
async: true,
url: '[CRM URL]/api/data/v8.2/' + '$batch',
data: bodyFetch,
beforeSend: function (xhr) {
//Specifying this header ensures that the results will be returned as JSON.
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("OData-MaxVersion", "4.0");
xhr.setRequestHeader("OData-Version", "4.0");
xhr.setRequestHeader("Prefer", "odata.include-annotations=*");
xhr.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_recordfetch");
},
//success callback
success: function (data, textStatus, xhr) {
data = JSON.parse(data.substring(data.indexOf('{'), data.lastIndexOf('}') + 1));
if (data != null) {
if (data.value == null) {
alert("success");
}
}
},
//error callback
error: function (xhr, textStatus, errorThrown) {
alert("failed");                          
}
});

Conclusion:

User can easily execute the long length FetchXML using the WEB API Batch Request.

To read more about FetchXML visit here.

Export Dynamics CRM Reports

Viewing all 33 articles
Browse latest View live