Using Xrm.WebApi method in Web Resource opened in a new window
Asked Answered
A

5

10

I have opened an HTML web resource in a new window using:

Xrm.Navigation.openWebResource(webResource, windowOptions, data);

This is an HTML web resource and it is loading the ClientObject in the head

<script type="text/javascript" src="../../../ClientGlobalContext.js.aspx" ></script>

then I have some JavaScript that is trying to retrieve a Contact

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
var promise = Xrm.WebApi.retrieveRecord("contact", contactId, "$select=contactid,firstname,lastname");`

but this is failing. I've step-traced into the Xrm.WebApi method and found the error is when it attempts to resolve "contact" to a Set Name

Code from Global.ashx

getEntitySetName: function(logicalName) {
    Mscrm.Utilities.addTelemetryLog("Xrm.Utility.getEntitySetName");
    var $v_0 = window.ENTITY_SET_NAMES || window.top.ENTITY_SET_NAMES;
    if (IsNull(this.$5H_1) && !isNullOrEmptyString($v_0))
        this.$5H_1 = JSON.parse($v_0);
    return this.$5H_1[logicalName.toLowerCase()]
},

For some reason the window.ENTITY_SET_NAMES object is null so an error (null reference) occurs

I've tried embedding my web resource into a CRM page and the code works correctly. The issue seems to be when the web resource is launched via Xrm.Navigation.openWebResource

Has anyone tried to use Xrm.WebApi in the context of an web resource opened with Xrm.Navigation.openWebResource? or does anyone know if there are additional steps required to retrieve data?


Update

ENTITY_SET_NAMES is initialised in main.aspx. I tried embedding my custom Web Resource directly into a new Main Form section and the retrieveRecord method works.

It appears this is a problem only when running the Web Resource from a new page via Xrm.Navigation.openWebResource


Update 2 - Response to Aron

I tried using window.parent as suggested below

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
var promise = parent.Xrm.WebApi.retrieveRecord("contact", contactId, "$select=contactid,firstname,lastname");`

and for good measure also tried window.parent.top

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
var promise = parent.top.Xrm.WebApi.retrieveRecord("contact", contactId, "$select=contactid,firstname,lastname");`

but both resulted in the same error

Argil answered 19/7, 2018 at 7:13 Comment(0)
A
3

My blog :)


To get this working I have implemented a hacky work-around.

I've been debugging the Xrm.WebApi method and it is failing on a line where it attempts to take the entityname and resolve it to the setname (plural). It does this by comparing the value passed into the retrieveRecord method and comparing it to a global variable ENTITY_SET_NAMES

In my example, it is trying to resolve contact to contacts

This variable is unfortunately not present and Xrm.WebApi throws an error

My work-around is to check for this variable, and if it is not present then create it! ENTITY_SET_NAMES is a JSON-parsable string which contains the logical name and set name for each entity.

window["ENTITY_SET_NAMES"] = window["ENTITY_SET_NAMES"] || JSON.stringify({
  "account" : "accounts",
  "contact" : "contacts"
});

Executing this line before any calls to Xrm.WebApi methods appears to work and I now get results

Here's the complete snippet:

window["ENTITY_SET_NAMES"] = window["ENTITY_SET_NAMES"] || JSON.stringify({
  "account" : "accounts",
  "contact" : "contacts"
});

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
Xrm.WebApi.retrieveRecord(
  "contact", 
  contactId, 
  "$select=contactid,firstname,lastname"
).then(
  function success(result) {
    console.log(result.firstname);
    // perform operations on record retrieval
  },
  function (error) {
    console.log(error.message);
    // handle error conditions
  }
);
Argil answered 20/7, 2018 at 2:5 Comment(0)
H
5

Sounds like a product bug within ClientGlobalContext.js.aspx, as this should give you whole context to work with.

Probably you can utilize window.opener.Xrm in this scenario, since it worked for window.opener.Xrm.Page.getAttribute it should also work for Xrm.WebApi.

You can try to access variable from opener window like this:

window["ENTITY_SET_NAMES"] = window["ENTITY_SET_NAMES"] || window.opener.top.ENTITY_SET_NAMES;
Hoffarth answered 25/7, 2018 at 18:45 Comment(1)
I have to specify top but it works: window.opener.top.ENTITY_SET_NAMESArgil
A
3

My blog :)


To get this working I have implemented a hacky work-around.

I've been debugging the Xrm.WebApi method and it is failing on a line where it attempts to take the entityname and resolve it to the setname (plural). It does this by comparing the value passed into the retrieveRecord method and comparing it to a global variable ENTITY_SET_NAMES

In my example, it is trying to resolve contact to contacts

This variable is unfortunately not present and Xrm.WebApi throws an error

My work-around is to check for this variable, and if it is not present then create it! ENTITY_SET_NAMES is a JSON-parsable string which contains the logical name and set name for each entity.

window["ENTITY_SET_NAMES"] = window["ENTITY_SET_NAMES"] || JSON.stringify({
  "account" : "accounts",
  "contact" : "contacts"
});

Executing this line before any calls to Xrm.WebApi methods appears to work and I now get results

Here's the complete snippet:

window["ENTITY_SET_NAMES"] = window["ENTITY_SET_NAMES"] || JSON.stringify({
  "account" : "accounts",
  "contact" : "contacts"
});

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
Xrm.WebApi.retrieveRecord(
  "contact", 
  contactId, 
  "$select=contactid,firstname,lastname"
).then(
  function success(result) {
    console.log(result.firstname);
    // perform operations on record retrieval
  },
  function (error) {
    console.log(error.message);
    // handle error conditions
  }
);
Argil answered 20/7, 2018 at 2:5 Comment(0)
A
2

As per this article, when referencing the main form from a Web Resource we have to reference the parent window. Though, it only references Xrm.Page and Xrm.Utility, it should also work with Xrm.WebApi...

An HTML web resource added to a form can’t use global objects defined by the JavaScript library loaded in the form. An HTML web resource may interact with the Xrm.Page or Xrm.Utility objects within the form by using parent.Xrm.Page or parent.Xrm.Utility, but global objects defined by form scripts won’t be accessible using the parent.

Please try parent.Xrm.WebApi.retrieveRecord("contact", contactId, "$select=contactid,firstname,lastname");

This article also demonstrates parent.Xrm.WebApi

Attractant answered 19/7, 2018 at 11:7 Comment(3)
great find Aron. Unfortunately it doesn't work. I've updated my question with my test resultsArgil
Thanks for the update. Since the code works when embedded in the form but fails when opened in a new window, it seems that opening the new window creates a new window object, which breaks window.ENTITY_SET_NAMES. Perhaps you can retrieve it from the parent window and set it on the child window to enable Xrm.WebApi. Or, when working in a new window, perhaps "roll your own" Web API calls. For that purpose Jason Lattimer's CRMRESTBuilder is very handy.Attractant
I couldn't retrieve it from the parent window - it was null. The solution I eventually settled on was to create my own ENTITY_SET_NAME global variable with only the values I need. I've added my own answer if you want to see more detailArgil
N
2

If you are going to use bound actions & functions you'll also need to add a similar variable to map entities to their primary id fields.

window["ENTITY_PRIMARY_KEYS"] = ['{"account":"accountid", "contact":"contactid"}'];
Numismatist answered 12/11, 2018 at 4:30 Comment(0)
C
0

Try using opener.Xrm to access the Xrm object in a standalone webresource opened from a form as described here in the parent.Xrm section: https://learn.microsoft.com/en-us/power-platform/important-changes-coming#some-client-apis-are-deprecated

"If the getContentWindow method doesn't work, you can use parent.Xrm to get to the Xrm object inside an HTML web resource. If the HTML web resource is opened in a new window, then you should use opener.Xrm instead."

var contactId = "8553DA63-11C9-E711-A824-000D3AE0CB84";
var promise = opener.Xrm.WebApi.retrieveRecord("contact", contactId, "$select=contactid,firstname,lastname");
Candlewick answered 28/6, 2022 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.