Walkthrough of Asynchronous call from <CustomRule> (RibbonDiff)

Walkthrough of Asynchronous call from <CustomRule>(RibbonDiff)

In following walkthrough I am demonstrating how to use EnableRule in Ribbon to call JavaScript function which will do Asynchronous call to CRM using REST and how to set Enable and Disable Ribbon Button

Assuming that Ribbon Customization is done and CustomRule is calling JavaScript function on EnableRule.

Following is how JavaScript. Here I am checking if logged in User is associated with current Entity record using Connections.

///<reference path=”XrmPage-vsdoc.js”/>
//Global Parameter
var isPartnerTeamMember = false;
var PageUI; 

function GetServerUrl() {

    var customServerURL = document.location.protocol + “//” + document.location.host + “/” + Xrm.Page.context.getOrgUniqueName();

    return customServerURL;

}

 

function CheckUserAccessOnPartner(PrimaryEntityTypeName, partnerObjectTypeCode, SelectedEntityTypeName, partnerId) {

    if (isPartnerTeamMember) {

        return true;

    }

    else {

        PageUI = window.top.opener.parent.Xrm.Page.ui;

        var context = Xrm.Page.context;

        var serverUrl = GetServerUrl();

        var userId = context.getUserId();

        var ODataPath = serverUrl + “/XRMServices/2011/OrganizationData.svc”;

        var retrieveReq = new XMLHttpRequest();

        retrieveReq.open(“GET”, ODataPath + “/ConnectionSet?$select=ConnectionId,Record1Id,Record1ObjectTypeCode,Record2Id,Record2ObjectTypeCode&$filter=Record1ObjectTypeCode/Value eq ” + partnerObjectTypeCode + ” and Record2ObjectTypeCode/Value eq 8 and Record1Id/Id eq guid'” + partnerId + “‘”, true);

        retrieveReq.setRequestHeader(“Accept”, “application/json”);

        retrieveReq.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);

        retrieveReq.onreadystatechange = function () {

            retrievePartnerConnectionsCallBack(this);

        };
        retrieveReq.send();
        return false;
    }
}

function retrievePartnerConnectionsCallBack(retrieveReq) {

    if (retrieveReq.readyState == 4 /* complete */) {

        if (retrieveReq.status == 200) {
            //Success
            var responseData = JSON.parse(retrieveReq.responseText).d;

            if (responseData != null && responseData.results != null && responseData.results.length > 0) {

                for (i = 0; i < responseData.results.length; i++) {

                    var record2Id = “{” + responseData.results[0].Record2Id.Id + “}”;

                    if (record2Id.toLowerCase() == Xrm.Page.context.getUserId().toLowerCase()) {

                        isPartnerTeamMember = true;

                        if (PageUI != null) {
                            PageUI.refreshRibbon();
                        }
                        break;
                    }
                }
            }
        }

        else {
            //errorHandler(retrieveReq);
        }
    }
}

 Key Point to note in above Script

  1. I am using Global variable to defined return value (isPartnerTeamMember) which is by default set to false.
  2. As first step I am checking isPartnerTeamMember and returning if it is true else calling REST query.
  3. In REST callback I am calling Xrm.Page.ui.refreshRibbon() method, which will reevaluate function and this time it will find isPartnerTeamMember as true and it will be returned from there.
  4. One of the important thing to note here is if you have having Ribbon button on SubGrid or associated view Xrm.Page.ui will be null for this you have to use window.top.opener.parent.Xrm.Page.ui (Thanks Daniel Cai !! for figuring out this)

Hope this Helps

Advertisements

CRM 2011 – Alternative to context.getServerUrl()

As all of you know context.getServerURL, returns the base server URL. The format of this Url can change depending on whether the user is connected to Microsoft Dynamics CRM 2011 On Premises, Microsoft Dynamics CRM Online, or working offline with Microsoft Dynamics CRM for Microsoft Office Outlook with Offline Access.

However there is one constrain using context.getServerURL as given in SDK Help –

The URL returned always returns the standard URL used to access the application. If you accessing the server locally using http://localhost or are using an IP address rather than the actual name of the server this will not be reflected in the value returned by this function. This means that if you are making web service calls or accessing Web resources Internet Explorer will apply security settings that apply to requests that cross domains. To avoid this, always connect to Microsoft Dynamics CRM using the standard URL.

So if user is accessing CRM using IP address, any call made to CRM using REST endpoint or SOAP endpoint will throw “Access Denied” error.

I have adopted following workaround for this problem which let user use ServerName as well as IP address for accessing CRM

Note: This approach does not work in CRM Online, you might have to tweek in little bit to get it work in CRM Online

Basically I am by passing context.getServerURL call and constructing ServerURL using Document.location property

var customServerURL = document.location.protocol + “//” + document.location.host + “/” + Xrm.Page.context.getOrgUniqueName();

For Silverlight Web Resources it is

stringserverUrl = string.Empty;
string orgUniqueName = string.Empty;
orgUniqueName = (string)GetContext().Invoke(“getOrgUniqueName”);

if (HtmlPage.Document.DocumentUri.Port != 80 && HtmlPage.Document.DocumentUri.Port != -1)
{
serverUrl =string.Format(“{0}://{1}:{2}/{3}”, HtmlPage.Document.DocumentUri.Scheme, HtmlPage.Document.DocumentUri.Host, HtmlPage.Document.DocumentUri.Port.ToString(), orgUniqueName);
}
else
{
serverUrl =string.Format(“{0}://{1}/{2}”, HtmlPage.Document.DocumentUri.Scheme, HtmlPage.Document.DocumentUri.Host, orgUniqueName);
}

Hope this helps