Archive

Archive for December 31, 2015

CRM 2016 Web API – Optimistic Concurrency

December 31, 2015 1 comment

Assume a scenario, you retrieved an Account and wanted to update the ‘Name’ field. But due to concurrency the same Account has changed on the server since you retrieved it and you may not want to complete the update.

So how to detect this situation and avoid concurrency issues? The answer is ‘Optimistic Concurrency’ patterns provided by Web API.

What’s Optimistic Concurrency

  • Optimistic concurrency can be used to detect whether an entity has been modified since it was last retrieved by using ‘ETag’ and ‘If-Match Header’.
  • Etag:
    • Each time when we retrieve an entity it will include a @odata.etag
  • eTag

    eTag

    • The value of this property is updated each time the entity is updated.
    • Refer this article how to fetch Etag.
  • If-Match Header
    • If-Match header with the ETag value can be used to check whether the current value on the server matches the one found when the user last retrieved the record.

Sample Script:

Key Points to perform Optimistic Concurrency:

  • Get the @odata.etag property of record up on retrieval.
  • ‘Status’ code would be 412, if the current record is different from the server.

function updateRecord() {
var clientURL = Xrm.Page.context.getClientUrl();
var accountId = “f26b5f92-5798-e511-80e3-3863bb2ead80”;
var req = new XMLHttpRequest()
req.open(“PATCH”, encodeURI(clientURL + “/api/data/v8.0/accounts(” + accountId + “)”), true);
req.setRequestHeader(“If-Match”, “W/\”632353\””);
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) {
req.onreadystatechange = null;
if (this.status == 204) {
var data = JSON.parse(this.response, dateReviver);
}
else if (this.status == 412) {
var error = JSON.parse(this.response).error;
alert(“Precondition Failed – ” + error.message);
}
else {
var error = JSON.parse(this.response).error;
alert(“Error updating Account – ” + error.message);
}
}
};

// Set Account record properties
req.send(JSON.stringify({ name: “Rajeev Pentyala” }));
}

function dateReviver(key, value) {
var a;
if (typeof value === ‘string’) {
a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] – 1, +a[3], +a[4], +a[5], +a[6]));
}
}
return value;
};

Server Response

  • Web API call fails with 412 code, if the Etag value sent with the If-Match header is different from the current value in server.
Optimistic Concurrency

Optimistic Concurrency

  • If the value had matched, a 204 status is expected.

🙂

Advertisement

CRM 2016 Web API – Retrieve a record

December 31, 2015 1 comment

Below is the sample script to retrieve an Account record using Web API.

Key Points to perform Retrieve:

  • Use ‘GET’ request while performing Retrieve
  • ‘Status’ code would be 200.

Sample Script:

function retrieveAccounts() {
var clientURL = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest()
req.open(“GET”, encodeURI(clientURL + “/api/data/v8.0/accounts?$select=name&$top=1”), 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) {
req.onreadystatechange = null;
if (this.status == 200) {
var data = JSON.parse(this.response, dateReviver);
if (data && data.value) {
for (var indxAccounts = 0; indxAccounts < data.value.length; indxAccounts++) {
var accountName = data.value[indxAccounts].name;
var eTag = data.value[indxAccounts][‘@odata.etag’];
}
}
}
else {
var error = JSON.parse(this.response).error;
alert(“Error retrieving Accounts – ” + error.message);
}
}
};

req.send(null);
}

function dateReviver(key, value) {
var a;
if (typeof value === ‘string’) {
a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] – 1, +a[3], +a[4], +a[5], +a[6]));
}
}
return value;
};

ETag:

  • Each time when we retrieve a record, it will include a @odata.etag field.

    Web API eTag

    Web API eTag

  • We don’t need to include it in a $select system query option.
  • The value of this property is updated each time the entity is updated.
  • This will be used while performing optimistic concurrency to detect whether an entity has been modified since it was last retrieved.

🙂

Categories: CRM 2016 Tags: , , ,