Archive
Power Apps portals | Query data using portals Web API (Public preview)
Portals Web API:
- The Portals Web API enables building a richer user experience inside Power Apps portals pages.
- We can use the Web API to perform create, update, and delete operations across all Dataverse tables from the portal pages.
- For example, you can create a new account, update a contact, or change the table permissions for a product by using the portals Web API instead of the Portal Management app.
Query data using portals Web API:
Web API operations in portals so far were limited to creating, updating, deleting, associating and disassociating tables. With this public preview, Portals will have the capability to retrieve data using GET requests through portals Web API.
Preview capabilities:
The feature provides the following capabilities during this public preview:
- Query records
- Apply system query options
- Request specific properties
- Filter results
- Order results
- Aggregate and grouping results
- Retrieve a count of rows
- Column comparison
- Retrieve related table records with a query
Refer the Docs link for documentation.
đ
[Step by Step] Postman tool with Microsoft Dataverse Web API
Couple of years ago, I’ve blogged Postman tool using Dynamics 365 online. In this article, lets go through the steps to connect Postman tool with Dataverse Web API.
While most of the steps are unchanged, there is a simplified way now to connect to Dataverse Web API with out the need of registering App in Azure AD. Lets get started.
Pre-requisites:
- Power Apps Environment (Subscribe to 30 days trial, if you have not one).
- Postman Desktop App. (Download here)
- Note: These steps will not work with Postman web version.
Get Dataverse Environment URL:
- Connect to Power Apps portal.
- Select the ‘Environment’ you wish to connect from Postman tool.
- Click on ‘Settings -> Advanced Settings’
- Copy the URL up to the ‘dynamics.com/’ from the new window as shown below.
- Add ‘.api’ before ‘.crm.dynamics.com’ to the URL.
- My Web API url looks as https://orgc721edd9.api.crm.dynamics.com/.
- Copy and Save this URL, which would be used in next steps.
Set up Postman Environment:
We would need ‘Workspace’ and ‘Environment’ to get started with Postman.
- Open the Postman tool and create a new ‘Workspace’ if not having already.
- Click on create a new ‘Environment’.
- In the ‘Add Environment’ screen, we need to add Variables related to ‘Dataverse’ which helps Postman to connect Dataverse Web API.
- Following 6 variables need to be configured.
- url : Dataverse environment URL captured in previous section.
- clientid: ’51f81489-12ee-4a9e-aaae-a2591f45987d’. This is special ID which allows to authenticate with out the need of registering App in Azure Active Directiry (AAD).
- version: 9.2
- webapiurl: {{url}}/api/data/v{{version}}/
- callback: https://callbackurl
- authurl: https://login.microsoftonline.com/common/oauth2/authorize?resource={{url}}
- Lets add the first Variable “url“. In the ‘INITIAL VALUE’ paste the Dataverse environment url copied in previous section.
- Repeat the step for next 5 variables and looks as below. Click ‘Add’ to save the Postman ‘Environment’.
Authorize Postman to Dataverse Environment:
Now that we have Postman Environment ready with required variables. Lets authorize and connect the Postman to Dataverse Web API. For that we need to complete ‘Authorization‘ and generate a new ‘Access Token’.
- Select to the new Postman ‘Environment’ created in previous section.
- Create a new GET ‘Request’ and select {{webapiurl}} variable as url.
- Click on ‘Authorization’ tab and select ‘TYPE’ as ‘OAuth 2.0’ and click on ‘Get New Access Token’.
- Provide details as below in the ‘Get New Access Token’ screen and click ‘Request Token’.
- In the next screen, provide the Office 365 credentials.
- Post successful authentication, a new ‘Access Token’ gets generated as below. Click ‘Use Token’.
- ‘Access Token’ expires every 1 hour and you would get “401 Unauthorized’ exception upon expiry.
- Click on ‘Get New Access Token’ if the Token expires to get a new Access Token. From 2nd time, Token generates instantly without any further sign-in.
Connect Postman to Dataverse Web API and query:
As we completed ‘Authorization’ and got the ‘Access Token’, we are good to query Dataverse API.
- Create a new GET ‘Request’ and select {{webapiurl}} variable as url.
- In the ‘Authorization’ tab, select the ‘Access Token’ generated and click ‘Send’.
- You should get the Response as below with 200 Status code.
- Below is the sample to fetch Top 3 Account records.
- Refer this documentation to Use Postman to perform operations with the Web API.
- Refer this documentation for more details.
đ
[Code Snippet] Authenticate and Perform Operations using D365 Web API and C#
As a continuation to my last article Different ways to connect authenticate dynamics 365Â , lets see how to Authenticate Dynamics Web API using C#.
Note: Be mindful that this approach is different than connecting to Dynamics 365 using Microsoft.XRM.Tooling.Connector dll approach. This article explains how to connect to D365 using Web API which is no SDK .dll approach.
Pre-requisites:
- Dynamics 365 subscription. Go for 30 days trail if not already have one.
- Register an App in “Azure Active Directory” and get ‘Application ID’ and other parameters.
- Visual Studio Console application
Steps to Register App in “Azure Active Directory”:
We need to register an application with Microsoft Azure Active Directory so that it can connect to the Microsoft Dynamics 365 server, authenticate using OAuth, and access the web services.
- Connect to Microsoft Office Admin Center.
- From the ‘Admin Centers’ menu, select ‘Azure Active Directory’.
- From the “Azure Active Directory admin center’, select ‘App registrations’ -> New application registration
- Provide below details
- Name – Provide name of the App. Can be any name minimum of 4 characters.
- Application Type – Choose ‘Native’ as we are going to call Web API from Console application
- Sign-on URL – Can be a valid URL. This you need to pass in the Console application.
- Click ‘Create’ to complete the App creation
- Post creation, open the App and copy the ‘Application ID’ which you need in Console application.
- Click on ‘Settings’ -> Required Permissions -> Add ‘Dynamics CRM Online’ -> Enable the permission as below
- Finally, select the App, click on ‘Endpoints’ and copy ‘OAuth 2.0 Authorization Endpoint‘ which you would need in Console Application.
Steps to connect to D365 WebAPI from Console Application:
After registering App in ‘Azure Active Directory’ now its time to connect to D365 Web API from Console Application.
- Create a new C# Console Application project
- Add below 2 Nuget packages to the project
- Newtonsoft.Json
- Microsoft.IdentityModel.Clients.ActiveDirectory
Code Snippet:
In the ‘Program.cs’ file add below
- Add Using Namespaces:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net;
- Add Global Variables:
// O365 User Name and Password
private const string userName = “rajeevpentyala@exploreSept18.onmicrosoft.com”;
private const string password = “YourPasswordHere”;
// D365 Application Url
private const string serviceUrl = “https://exploresept18.crm.dynamics.com”;
// Azure APP Application Id
private const string applicationId = “1549b5b3-XXXX-XXXX-94be-7a8eeaf3e081”;
// Redirct Uri specified during registration of application
private const string RedirectUri = “https://localhost”;
// OAuth 2.0 Authorization Endpoint copied from Azure APP
private const string authorityUri = “https://login.microsoftonline.com/9e3039aa-XXXX-XXXX-80e1-f67d40bd01cf/oauth2/authorize”;private static AuthenticationResult authResult = null;
- Main Method:
private static void Main(string[] args){
// Code to connect to D365
var credentials = new UserPasswordCredential(userName, password);
var context = new AuthenticationContext(authorityUri);
authResult = context.AcquireTokenAsync(serviceUrl, applicationId, credentials).Result;// Call CRUD operations
// Task.WaitAll(Task.Run(async () => await ExecuteWhoAmI()));
// Task.WaitAll(Task.Run(async () => await CreateRecord()));
// Task.WaitAll(Task.Run(async () => await RetrieveContacts()));}
- Code to call WhoAmIRequest:
private static async Task ExecuteWhoAmI(){
var httpClient = new HttpClient{
BaseAddress = new Uri(serviceUrl),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add(“OData-MaxVersion”, “4.0”);
httpClient.DefaultRequestHeaders.Add(“OData-Version”, “4.0”);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken);// Add this line for TLS complaience
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;// Call WhoAmI
var retrieveResponse = await httpClient.GetAsync(“api/data/v9.0/WhoAmI”);
if (retrieveResponse.IsSuccessStatusCode){
var jRetrieveResponse = JObject.Parse(retrieveResponse.Content.ReadAsStringAsync().Result);var currUserId = (Guid)jRetrieveResponse[“UserId”];
var businessId = (Guid)jRetrieveResponse[“BusinessUnitId”];Console.WriteLine(“My User Id – ” + currUserId);
Console.WriteLine(“My User Id – ” + businessId);
Console.ReadLine();
}
}
- Code to Retrieve Records:
private static async Task RetrieveContacts(){
var httpClient = new HttpClient{
BaseAddress = new Uri(serviceUrl),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add(“OData-MaxVersion”, “4.0”);
httpClient.DefaultRequestHeaders.Add(“OData-Version”, “4.0”);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken);// Add this line for TLS complaience
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;// Retrieve Contacts
var retrieveResponse = await httpClient.GetAsync(“api/data/v9.0/contacts”);
if (retrieveResponse.IsSuccessStatusCode){
var jRetrieveResponse = JObject.Parse(retrieveResponse.Content.ReadAsStringAsync().Result);dynamic collContacts = JsonConvert.DeserializeObject(jRetrieveResponse.ToString());
foreach (var data in collContacts.value){
Console.WriteLine(“Contact Name – ” + data.fullname.Value);
}Console.ReadLine();
}
}
- Code to Create Record:
private static async Task CreateRecord(){
JObject contact1 = new JObject{
{ “firstname”, “Peter” },
{ “lastname”, “Cambel” },
{ “annualincome”, 80000 }
};contact1[“jobtitle”] = “Junior Developer”;
var httpClient = new HttpClient{
BaseAddress = new Uri(serviceUrl + “/api/data/v9.0/”),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add(“OData-MaxVersion”, “4.0”);
httpClient.DefaultRequestHeaders.Add(“OData-Version”, “4.0”);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken);// Add this line for TLS complaience
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, “contacts”){
Content = new StringContent(contact1.ToString(), Encoding.UTF8, “application/json”)
};HttpResponseMessage response = await httpClient.SendAsync(request);if (response.StatusCode == HttpStatusCode.NoContent) //204 {
Console.WriteLine(“POST succeeded, entity created!”);
//optionally process response message headers or body here, for example:
var entityUri = response.Headers.GetValues(“OData-EntityId”).FirstOrDefault();// Update the Contact record
Task.WaitAll(Task.Run(async () => await UpdateRecord(entityUri)));// Delete the contact record
Task.WaitAll(Task.Run(async () => await DeleteRecord(entityUri)));
}
else{
Console.WriteLine(“Operation failed: {0}”, response.ReasonPhrase);
throw new CrmHttpResponseException(response.Content);
}
}
- Code to Update Record:
private static async Task UpdateRecord(string contactUri){
JObject contact1Add = new JObject{
{ “annualincome”, 80000 },
{ “jobtitle”, “Junior Developer” }
};var httpClient = new HttpClient{
BaseAddress = new Uri(serviceUrl + “/api/data/v9.0/”),
Timeout = new TimeSpan(0, 2, 0)
};httpClient.DefaultRequestHeaders.Add(“OData-MaxVersion”, “4.0”);
httpClient.DefaultRequestHeaders.Add(“OData-Version”, “4.0”);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken);HttpRequestMessage updateRequest1 = new HttpRequestMessage(new HttpMethod(“PATCH“), contactUri){
Content = new StringContent(contact1Add.ToString(), Encoding.UTF8, “application/json”)
};
HttpResponseMessage updateResponse1 = await httpClient.SendAsync(updateRequest1);if (updateResponse1.StatusCode == HttpStatusCode.NoContent) //204 {
//Console.WriteLine(“Contact ‘{0} {1}’ updated with job title” +
// ” and annual income.”, contactUri.GetValue(“firstname”),
// contactUri.GetValue(“lastname”));
}
else{
Console.WriteLine(“Failed to update contact for reason: {0}”, updateResponse1.ReasonPhrase);
throw new CrmHttpResponseException(updateResponse1.Content);
}}
- Code to Delete Record:
private static async Task DeleteRecord(string contactUri){
var httpClient = new HttpClient{
BaseAddress = new Uri(serviceUrl + “/api/data/v9.0/”),
Timeout = new TimeSpan(0, 2, 0)
};httpClient.DefaultRequestHeaders.Add(“OData-MaxVersion”, “4.0”);
httpClient.DefaultRequestHeaders.Add(“OData-Version”, “4.0”);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken);var response = httpClient.DeleteAsync(contactUri).Result;
if (response.IsSuccessStatusCode) //200-299 {
Console.WriteLine(“Contact has been deleted!!!”);
}
else if (response.StatusCode == HttpStatusCode.NotFound) //404 {
//Entity may have been deleted by another user or via cascade delete.
}
else //Failed to delete {
Console.WriteLine(“Error while deletion; Message: ” + response.Content);
}
}
đ
D 365 Development â Different ways to connect/authenticate Dynamics 365
There was a question posted on my blog by a Dynamics 365 newbie developer on how to authenticate to Dynamics 365 online from his console application.
In this article I am going to detail various ways to connect to Dynamics 365.
Option 1 – Connect using Dynamics 365 SDK assemblies:
- You need Dynamics 365 SDK assemblies, If you are creating plug-ins, custom workflow activities, or custom XAML workflows and performing operations (i.e., Create/Update/Execute/Retrieve)
- Refer Steps to create a basic plug-in
- Download the latest SDK assemblies from nuget.
Option 2 – Connect using XRM Tooling assemblies:
- If you are building .Net applications (i.e., Console/Web/Windows) use the XRM Tooling assemblies to connect to the Dynamics Application.
- XRM tooling enables you to connect to your Dynamics 365 instance by using connection strings.
- Refer article for different types of Connection strings based on your Dynamics deployment (i.e., One-prem/IFD/Office 365 etc..)
- Below is the sample code to connect to your instance from Console:
Prerequisites:
- Download the latest SDK assemblies from nuget in your console application.
- Make sure you refer below .dlls in your console class file.
- using Microsoft.Xrm.Sdk;
- using Microsoft.Xrm.Tooling.Connector;
App.Config:
// Add below Connection string to your console’s App.config file
<connectionStrings>
<add name=”Xrm” connectionString=”Url=https://{orgname}.crm.dynamics.com; Username=rajeevpentyala@yourdomain.onmicrosoft.com; Password=XXXXXXX;authtype=Office365;Timeout=20″ />
</connectionStrings>
Code:
// Declare the Service Variables
private static OrganizationServiceProxy _serviceProxy;
private static IOrganizationService _service;
// Read the connection string configured in App.config file
var connectionString = ConfigurationManager.ConnectionStrings[“Xrm”].ConnectionString;
var crmConn = new CrmServiceClient(connectionString);
using (_serviceProxy = crmConn.OrganizationServiceProxy) {
_service = _serviceProxy;
var reqWhoAmI = new WhoAmIRequest();
var resp = (WhoAmIResponse)_service.Execute(reqWhoAmI);
var buID = resp.OrganizationId.ToString();
var userID = resp.UserId.ToString();
}
- Refer my post on steps to connect to D 365 using Xrm.Tooling.Connector
Option 3 – Connect using Dynamics 365 Web API:
- What if you want to connect to Dynamics from a Non- .NET applications (i.e., Java/PHP applications), the solution is Web API.
- Web API provides development experience that can be used across a wide variety of programming languages, platforms, and devices.
- Web API uses no DLL approach; Unlike above 2 approaches (i.e., XRM Tooling/SDK Assemblies), you donât need to refer assemblies to connect to Web API.
- There are 3 different ways to connect to Web API
- Using JavaScript in from Dynamics web resources (i.e., Jscript files, HTML, Ribbon). We donât need to include any authentication code as the logged-in user is already authenticated by the application.
- Refer this article
- If your Dynamics 365 is On-premise, you can authenticate Web API by passing Userâs network credentials.
- If your Dynamics 365 is Online or IFD, you must use OAuth to connect.
- The recommended authentication API for use with the Dynamics 365 Web API is Azure Active Directory Authentication Library (ADAL)
- Using JavaScript in from Dynamics web resources (i.e., Jscript files, HTML, Ribbon). We donât need to include any authentication code as the logged-in user is already authenticated by the application.
- Refer this article on steps to connect to Web API.
- Web API is very convenient to use and test.
- With Postman tool you can connect to Web API and perform operations. Refer article
Below is the Flow diagram gives idea on when to use which option among the 3 options:
đ
[Step by Step] Configure Server-to-Server (S2S) authentication using Azure AD and Application User – Dynamics 365
In this article I am going to explain, what is âApplication Userâ and how it helps to establish using Server-to-Server (S2S) authentication and Azure Active Directory
To explain the S2S authentication simpler, letâs take an integration requirement
- You have an ASP.Net Web Application
- You need pull the Contacts from a CRM organization and display in the ASP.Net Web Page
The conventional design approach for the above requirement would be
- Establish the CRM connection in your ASP.Net page by passing CRM User credentials
- Make a Retrieve call to CRM
- Read and bind the Contacts to a grid.
To implement the above design you need to have a paid CRM User credentials to interact with your Dynamics CRM organization.
So what is S2S authentication and how is it different from the legacy integration model we discussed above.
Server-to-Server (S2S) authentication:
- S2S authentication means you donât need to use a paid Dynamics 365 user license when you connect to Dynamics 365 tenants.
- We will use a special user (i.e., Application User)
- Best part is, you can connect to D365 and make server calls from your application (i.e.,Web/Console) with no Dynamics SDK dlls and no ‘UserID/Password’.
What is this âApplication Userâ:
- âApplication Userâ is a âsystemuserâ record of type âApplication Userâ
- There is no license fee for the âApplication Userâ account
How an âApplication Userâ account achieve the S2S authentication:
- Â âApplication Userâ with conjunction of Azure Active Directory (Azure AD) will establish S2S authentication.
- We first generates an âApplication IDâ in Azure AD which we set in âApplication Userâ in Dynamics.
Lets see the step by step approach to achieve S2S authentication.
- Pre-requisites:
- Dynamics 365 instance
- Azure Subscription with same Office 365 account used for your D365 instance.
- High Level Steps
- Generate âApplication IDâ and âKeysâ in âAzureâ
- Add a new User in âAzure Active Directoryâ (Azure AD)
- Create a new âApplication Userâ in Dynamics 365
Step 1 – Generate âApplication IDâ and âKeysâ in âAzureâ:
- Connect to your Azure
- Go to âApp registrationsâ service
- Create a âNew application registrationâ
- Note: ‘Sign-on URL’ can be any valid URL.
- Copy the generated âApplication IDâ (This is needed while creating âApplication Userâ in CRM)
- Generate âKeysâ (You need the âKeyâ to establish connection in your Web Application/Console Application)
- Save the âKeyâ (Note: You cannot read the key if you move away from the screen)
Step 2 – Add a new User in âAzure Active Directoryâ (Azure AD):
- Connect to your Azure
- Go to âUsersâ service
- Create a âNew Userâ
- Note: ‘Password’ auto generates once you save. You don’t need to copy as this is not required further.
- Once the User saved, copy the âUser Nameâ (This is needed while creating âApplication Userâ in CRM)
Step 3 – Create a new âApplication Userâ in Dynamics 365:
This step we are going to create an ‘Application User’ in D365 by copying the details generated in Azure
- Connect to Dynamics 365
- Go to âSettings -> Security -> Users
- Switch the view to âApplication Usersâ and click âNewâ
- In the âNew Userâ screen
- Set âUser Nameâ with the âUser Nameâ copied from âAzureâ
- Set âApplication IDâ with the âApplication IDâ copied from âAzureâ
- Save the User and once saved, you notice the auto populated âApplication ID URIâ and âAzure AD Object IDâ
- Assign a âSecurity Roleâ
- âSecurity Roleâ must be a Custom Security Role and you cannot assign OOB role.
- For this exercise, you might want to copy any existing OOB Security Role.
All right! We are all set and now its time to test S2S authentication from your console.
S2S Authentication Code Snippet:
Prerequisites:
- Install âADALâ and âNewtonSoftâ NuGet packages
 Code:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
private static async Task GetContactsAsync()
{
// Your Dynamics Web API URL
string api = “https://docmigrate.api.crm.dynamics.com/api/data/v9.0/”;AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(api)).Result;
// Set ‘Application ID’ and ‘Key’ generated from Azure
var creds = new ClientCredential(“e4ac3a78-xxxx-403a-a94c-xxxxxxx”, “hEo/xxxxxxxS+LEiYHpxxxxxxxRe8xg0=”);AuthenticationContext authContext = new AuthenticationContext(ap.Authority);
var token = authContext.AcquireTokenAsync(ap.Resource, creds).Result.AccessToken;using (HttpClient httpClient = new HttpClient())
{
httpClient.Timeout = new TimeSpan(0, 2, 0);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Bearer”, token);// Retrieve Top 1 Contact
HttpResponseMessage response = await httpClient.GetAsync(api + “/contacts?$top=1”);// Parse the response
if (response.IsSuccessStatusCode)
{
JObject contact = JsonConvert.DeserializeObject<JObject>(await response.Content.ReadAsStringAsync());var contactName = contact.GetValue(“fullname”);
}
}
}
đ
Retrieve and Update record with alternate key using Web API â CRM 2016
Alternative Keys are useful to retrieve or update the records without the need of GUID. It avoids the overhead of retrieving record’s GUID while update operation.
In conventional way, to update an Account record from external web application, you would need to get the GUID first and then update.
With alternate key, you can configure any of your field of type (Single Line of Text, Whole Number or Decimal Number) as Alternate key and use instead of GUID to retrieve or update.
We can have up to 5 different alternate keys per entity.
Sample C# code to update record with out GUID:
- I configured “Account Number” as alternate key.
- I have an Account with ‘Account Number’ as ‘Acct123’Â and below is the code to update record. Notice that I did not provide the record GUID.
Entity account = new Entity(“account”, “accountnumber”, “Acct123”);
account[“name”] = “Rajeev Modified”;
service.Update(account);
Create an Alternate key
- Go to Customization–> Entity–> Keys –> New
- Click “Ok”
- Wait for few seconds so that the background workflow complete creation of required indexes.
Jscript to retrieve using Alternate key:
- Below is the script to retrieve a record with alternate key using web api.
function getAccountByAlternateKey() {
try {
var clientUrl = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest();
// Account Number as an ‘Alternate key’
req.open(“GET”, encodeURI(clientUrl + “/api/data/v8.0/accounts(accountnumber=’Acct123′)“), true);
// If multiple keys as ‘Alternate key’
//req.open(“GET”, encodeURI(clientUrl + “/api/data/v8.0/accounts(name=’Rajeev’,emailaddress1=’rajeev@live.com’)”), 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) {
var data = JSON.parse(this.response);
var dat = data.value;
for (var i = 0; i < dat.length; i++) {
var accountId = dat[i].accountid;
Xrm.Utility.alertDialog(“Account Id : ” + accountId);
}
}
else {
var error = JSON.parse(this.response).error;
alert(“Error retrieving Account- ” + error.message);
}
}
};req.send();
} catch (e) {
alert(“Error in getAccountByAlternateKey – ” + e.description);
}
}
JScript to Update Record Using Alternate Key
function updateAccountByAlternateKey() {
try {
var clientUrl = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest();
// Account Number as an ‘Alternate key’
req.open(“PATCH“, encodeURI(clientUrl + “/api/data/v8.0/accounts(accountnumber=’Acct123′)“), 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 == 204) {
var accountUri = this.getResponseHeader(“OData-EntityId”);//get EntityId from ResponseHeader of Created Record
var accountID = accountUri.split(/[()]/);
accountID = accountID[1];Xrm.Utility.alertDialog(“Updated Account ID : ” + accountID);
}
}
};// Set Account Object
var objAccount = {};
objAccount.name = “Rajeev Modified”;
objAccount.revenue = 123456;//convert JSON object to string
var body = JSON.stringify(objAccount);req.send(body);
} catch (e) {
alert(“Error in updateAccountByAlternateKey – ” + e.description);
}
}
Refer article  for more details.
đ
JScript to Create record and its related record using Web API – CRM 2016
Below is the script snippet to create ‘Account’ record using Web API.
function createAccount() {
var clientUrl = Xrm.Page.context.getClientUrl();var req = new XMLHttpRequest()
req.open(“POST”, encodeURI(clientUrl + “/api/data/v8.0/accounts”), 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.setRequestHeader(“Prefer”, “odata.include-annotations=*”);// Set Account Object
var objAccount = {};
objAccount.name = “Rajeev Associates”;
objAccount.creditonhold = false;
objAccount.accountcategorycode = 1;
objAccount.revenue = 123456;// Create new Contact and Set as ‘Primary Contact’
objAccount.primarycontactid = {};
objAccount.primarycontactid.firstname = “Hello”;
objAccount.primarycontactid.lastname = “Lobo”;// Set existing Contact as ‘Primary Contact’
//objAccount[‘primarycontactid@odata.bind’] = “/contacts(” + { contact GUID } + “)”;//convert JSON object to string
var body = JSON.stringify(objAccount);
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 204) {
var accountUri = this.getResponseHeader(“OData-EntityId”);// Get Account GUID
var accountID = accountUri.split(/[()]/);
accountID = accountID[1];Xrm.Utility.alertDialog(“Created Account ID : ” + accountID);
}
}
};req.send(body);
}
- To set the lookup you need to fetch the Contact GUID first and set to ‘primarycontactid@odata.bind’. ‘@odata.bind’ is suffix and ‘primarycontactid‘ is the schema name of lookup.
- Below is sample script to retrieve Contact GUID by Fullname
function getPrimaryContact() {
var clientUrl = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest();
req.open(“GET”, encodeURI(clientUrl + “/api/data/v8.0/contacts?$select=fullname&$filter=fullname eq ‘John Miller'”), 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) {
var data = JSON.parse(this.response);
var dat = data.value;// Loop through ‘Contact’ result set
for (var i = 0; i < dat.length; i++) {// Get ‘Contact ID’ from Contact record.
var contactId = dat[i].contactid;
if (contactId) {Xrm.Utility.alertDialog(“Contact ID : ” + contactId);
}
}
}
else {
var error = JSON.parse(this.response).error;
alert(“Error retrieving contact – ” + error.message);
}
}
};req.send();
}
đ
JScript to retrieve and execute view (Predefined Query) using Web API – CRM 2016
Assume you would need to retrieve âActive Accountsâ from your script, you can either retrieve by building FetchXML from scratch or simply use Web APIÂ to execute existing âActive Accountsâ view query with no need of writing Fetch XML.
Using Web API we can retrieve and execute predefined queries (i.e., System view and Personal view queries).
Below are the steps to retrieve and execute ‘System view’ query using CRM WebAPI
- Get the GUID of View by Name.
- Execute the view and fetch the result set. (Columns of the result set would be same as ‘System View’ columns)
Script
function executeView(viewName) {
try {
var clientUrl = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest();
// Get ‘Active Accounts’ GUID
req.open(“GET”, encodeURI(clientUrl + “/api/data/v8.0/savedqueries?$select=name,savedqueryid&$filter=name eq ‘” + viewName + “‘”), 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) {
var data = JSON.parse(this.response);
var dat = data.value;
for (var i = 0; i < dat.length; i++) {
var viewId = dat[i].savedqueryid;
alert(“View Id : ” + viewId);
if (viewId) {
executeViewQuery(viewId);
}
}
}
else {
var error = JSON.parse(this.response).error;
alert(“Error while fetching view id” + error.message);
}
}};
req.send();
} catch (e) {
alert(“Error in getViewId” + e.description);
}
}
function executeViewQuery(viewId) {
try {
var clientUrl = Xrm.Page.context.getClientUrl();
var req = new XMLHttpRequest()
req.open(“GET”, encodeURI(clientUrl + “/api/data/v8.0/accounts?savedQuery=” + viewId + “”), 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”);
// Include this to get Lookup and Optionset text
req.setRequestHeader(“Prefer”, “odata.include-annotations=OData.Community.Display.V1.FormattedValue”);
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 200) {
var data = JSON.parse(this.response);
var dat = data.value;
for (var i = 0; i < dat.length; i++) {
alert(“Account Name – ” + dat[i].name);
// Read Lookup name (i.e.,Primary Contact)
alert(“Primary Contact – ” + dat[i][‘_primarycontactid_value@OData.Community.Display.V1.FormattedValue’]);
}
}
else {
var error = JSON.parse(this.response).error;
alert(“Error while executing view query” + error.message);
}
}
};
req.send();
} catch (e) {
alert(“Error in getViewId” + e.description);
}
}
The result set would look as below.
How Do I call this method:
- Copy and paste above two functions.
- Pass the ‘System View’ name to executeView({View Name}) function.
// To Retrieve and Execute ‘Active Accounts’ view
executeView(“Active Accounts”);
Note: To use “Personal View”, change the “savedqueries” to “userqueries” in Wab API URI.
Refer MSDN Article for more details.
đ
CRM 2016 Web API â Impersonate User
In CRM, Impersonation is possible in Plug-ins (using âRun Asâ while registering Plug-in step) or using âCallerIdâ property while instantiating OrganizationServiceProxy.
What if I have to impersonate âRetriveâ operation from Jscript? This was not possible.
With advent of CRM Web API with CRM 2016 we can impersonate in Jscript.
What is a Web API :
- The Web API implements the OData (Open Data Protocol), version 4.0.
- The new Web API provides better capabilities over the OData service introduced with CRM 2011 and OData service will be deprecating with this release.
- It provides a modern, RESTful web service you can use to interact with data in CRM using a wide variety of platforms, programming languages and devices
- The Web API will provide parity with the existing organization service (SOAP endpoint).
- You can perform all operations using HTTP requests with the Web API located at [organization uri]/api/data/v8.0/
Impersonate another User using Web API:
- To impersonate a user, add a request header named MSCRMCallerID with a GUID value equal to the impersonated userâs systemuserid before sending the request to the web service.
Sample Script with impersonation to create an Account Record
function createAccount() {
var clientURL = Xrm.Page.context.getClientUrl();
var impersonateUserId = “7eb682f1-ca75-e511-80d4-00155d2a68d1”;// GUID
var req = new XMLHttpRequest()
req.open(“POST”, encodeURI(clientURL + “/api/data/v8.0/accounts”), 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”);
// Set the Caller ID; GUID of User
req.setRequestHeader(“MSCRMCallerID”, impersonateUserId);
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 204) {
var accountUri = this.getResponseHeader(“OData-EntityId”);
alert(“New account created; URI: ” + accountUri)
}
else {
var error = JSON.parse(this.response).error;
alert(“Error creating Account – ” + error.message);
}
}
};// Set Account record properties
req.send(JSON.stringify({ name: “Rajeev Pentyala”, description: “Account created using Web API”, revenue: 5000000 }));
}
đ
CRM 2016 Web API â Optimistic Concurrency
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
-
- 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.
- If the value had matched, a 204 status is expected.
đ