Tuesday, 7 April 2020

Connecting Dynamics 365 Web api using external HTML page

Connecting Dynamics 365 Web api using external HTML page

Here we are discussing on how we can connect Dynamics 365 Web Api using external application. Below are the steps we need to follow in order to achieve our goal.
Note: if the HTML page is not giving any result or not able to load browser cache (CRM user token) then your need to clear Brower cache and try to load HTML again.



 1.       Login in to https://portal.azure.com
2.       Provide your CRM username and password to log in into azure. Once you login create an application as below screen shot
Azure Active DirectoryàApp RegistrationàClick on New application registration

3.       Provide Name, select Application Type as “Web App / API” and provide Sing –on URL as CRM URL as below.



4.       Open the newly created application and click on Settings.

5.       Click on Keys and provide “Description” as key name and “Expires” as Never expires. Once you click on Save it generates a key. make sure you copy the key otherwise it will be hidden for the next time.



6.       Open the same application and click on settings. Click on Reply URL’s and provide the complete URL from where you are calling (your client application URL).




7.       Copy the Appicaiton ID/Client ID, your application URL paste in html code.


    After every set up done copy below HTML code and try to run on your browser.

<!DOCTYPE html>
<html>
<head>
 <title>Simple SPA</title>
 <meta charset="utf-8" />
 <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>

 <!--<script src="adal.js"></script>-->
 <script>
  "use strict";
  //Set these variables to match your environment
  var organizationURI = "https://agsfstrainings.crm8.dynamics.com"; //The URL to connect to CRM Online
  var tenant = "agsfstrainings.onmicrosoft.com"; //The name of the Azure AD organization you use
  var clientId = "c58b9636-71ea-4588-be48-39538d6488a1"; //The ClientId you got when you registered the application
  var pageUrl = "http://localhost:60347//HtmlPage1.html"; //The URL of this page in your development environment when debugging.
  var user, authContext, message, errorMessage, loginButton, logoutButton, getAccountsButton, accountsTable, accountsTableBody;
  var accountsQuery = "/api/data/v8.0/accounts?$select=name,address1_city&$top=10";
  var apiVersion = "/api/data/v8.0/";
  //Configuration data for AuthenticationContext
  var endpoints = {
   orgUri: organizationURI
  };
  window.config = {
   tenant: tenant,
   clientId: clientId,
   postLogoutRedirectUri: pageUrl,
   endpoints: endpoints,
   cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
  };
  document.onreadystatechange = function () {

   if (document.readyState == "complete") {
    //Set DOM elements referenced by scripts
    message = document.getElementById("message");
    errorMessage = document.getElementById("errorMessage");
    loginButton = document.getElementById("login");
    logoutButton = document.getElementById("logout");
    //getAccountsButton = document.getElementById("getAccounts");
    accountsTable = document.getElementById("accountsTable");
    accountsTableBody = document.getElementById("accountsTableBody");
    //Event handlers on DOM elements
    loginButton.addEventListener("click", login);
    logoutButton.addEventListener("click", logout);
    //getAccountsButton.addEventListener("click", getAccounts);
    //call authentication function
    authenticate();
    if (user) {

     loginButton.style.display = "none";
     logoutButton.style.display = "block";
     //getAccountsButton.style.display = "block";
     var helloMessage = document.createElement("p");
     helloMessage.textContent = "Hello " + user.profile.name;
     message.appendChild(helloMessage)
    }
    else {
     loginButton.style.display = "block";
     logoutButton.style.display = "none";
     //getAccountsButton.style.display = "none";
    }
   }
  }
  // Function that manages authentication
  function authenticate() {
   //OAuth context
   authContext = new AuthenticationContext(config);
   // Check For & Handle Redirect From AAD After Login
   var isCallback = authContext.isCallback(window.location.hash);
   if (isCallback) {
    authContext.handleWindowCallback();
   }
   var loginError = authContext.getLoginError();
   if (isCallback && !loginError) {
    window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
   }
   else {
    errorMessage.textContent = loginError;
   }
   user = authContext.getCachedUser();
  }
  //function that logs in the user
  function login() {
   authContext.login();
  }
  //function that logs out the user
  function logout() {
   authContext.logOut();
   accountsTable.style.display = "none";
   accountsTableBody.innerHTML = "";
  }
  //function that initiates retrieval of accounts
  function getAccounts() {

   //getAccountsButton.disabled = true;
   var retrievingAccountsMessage = document.createElement("p");
   retrievingAccountsMessage.textContent = "Retrieving 10 accounts from " + organizationURI + "/api/data/v8.0/accounts";
   message.appendChild(retrievingAccountsMessage)
   // Function to perform operation is passed as a parameter to the aquireToken method
   authContext.acquireToken(organizationURI, retrieveAccounts)
  }
  //function that initiates retrieval of accounts
  function getAccounts() {

   //getAccountsButton.disabled = true;
   var retrievingAccountsMessage = document.createElement("p");
   retrievingAccountsMessage.textContent = "Retrieving 10 accounts from " + organizationURI + "/api/data/v8.0/accounts";
   message.appendChild(retrievingAccountsMessage)
   // Function to perform operation is passed as a parameter to the aquireToken method
   authContext.acquireToken(organizationURI, retrieveAccounts)
  }
  function createContacts() {

   var retrievingAccountsMessage = document.createElement("p");
   retrievingAccountsMessage.textContent = "Creating contact record....!";
   //getAccountsButton.disabled = true;

   message.appendChild(retrievingAccountsMessage)
   // Function to perform operation is passed as a parameter to the aquireToken method
   authContext.acquireToken(organizationURI, createContactRecords)
  }
  function createContactRecords(error, token) {

   // Handle ADAL Errors.
   if (error || !token) {
    errorMessage.textContent = 'ADAL error occurred: ' + error;
    return;
   }
   var contactObj = {};
   contactObj["firstname"] = "Bangar";
   contactObj["lastname"] = "Raju";
   contactObj["parentcustomerid_account@odata.bind"] = "/accounts(475B158C-541C-E511-80D3-3863BB347BA8)";
   var req = new XMLHttpRequest()
   //"/api/data/v8.2/" + entityPlurarName, false
   req.open("POST", encodeURI(organizationURI + apiVersion + "contacts"), true);
   //Set Bearer token
   req.setRequestHeader("Authorization", "Bearer " + token);
   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(JSON.stringify(contactObj));
   req.onreadystatechange = function () {
    if (this.readyState == 4 /* complete */) {

     req.onreadystatechange = null;
     if (req.status === 204) {

      var uri = req.getResponseHeader("OData-EntityId");
      var regExp = /\(([^)]+)\)/;
      var matches = regExp.exec(uri);
      var contactId = matches[1];
      var retrievingAccountsMessage = document.createElement("p");
      retrievingAccountsMessage.textContent = "Contact record created successfully with ID:" + contactId;
      message.appendChild(retrievingAccountsMessage)
     }
     else {
      var error = JSON.parse(this.response).error;
      console.log(error.message);
      errorMessage.textContent = error.message;
     }
    }
   };
  }
  //Function that actually retrieves the accounts
  function retrieveAccounts(error, token) {

   // Handle ADAL Errors.
   if (error || !token) {
    errorMessage.textContent = 'ADAL error occurred: ' + error;
    return;
   }
   var req = new XMLHttpRequest()
   req.open("GET", encodeURI(organizationURI + accountsQuery), true);
   //Set Bearer token
   req.setRequestHeader("Authorization", "Bearer " + token);
   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 accounts = JSON.parse(this.response).value;
      renderAccounts(accounts);
     }
     else {
      var error = JSON.parse(this.response).error;
      console.log(error.message);
      errorMessage.textContent = error.message;
     }
    }
   };
   req.send();
  }
  //Function that writes account data to the accountsTable
  function renderAccounts(accounts) {
   accounts.forEach(function (account) {
    var name = account.name;
    var city = account.address1_city;
    var nameCell = document.createElement("td");
    nameCell.textContent = name;
    var cityCell = document.createElement("td");
    cityCell.textContent = city;
    var row = document.createElement("tr");
    row.appendChild(nameCell);
    row.appendChild(cityCell);
    accountsTableBody.appendChild(row);
   });
   accountsTable.style.display = "block";
  }

  function doOperationOnCRM() {
   var e = document.getElementById("crmOperation")
   var typeOfOperation = e.options[e.selectedIndex].value
   var retrievingAccountsMessage = document.createElement("p");
   retrievingAccountsMessage.textContent = '';
   switch (typeOfOperation) {
    case "1": getAccounts();
     break;
    case "2": //To Do
     break;
    case "3": createContacts(); break;
    case "4": break;//To Do
    default:
   }
  }
 </script>
 <style>
  body {
   font-family: 'Segoe UI';
  }

  table {
   border-collapse: collapse;
  }

  td, th {
   border: 1px solid black;
  }

  #errorMessage {
   color: red;
  }

  #message {
   color: green;
  }
 </style>
</head>
<body>
 <button id="login">Login</button>
 <button id="logout" style="display:none;">Logout</button>
 <br />
 <select id="crmOperation" onchange="doOperationOnCRM()">
  <option value="0">---Select---</option>
  <option value="1">Retrieve Accounts</option>
  <option value="2">Execute Fetch to get Accounts</option>
  <option value="3">Create Contacts</option>
  <option value="4">Create Task</option>
 </select>
 <button id="getAccounts" style="display:none;">Get Accounts</button>
 <table id="accountsTable" style="display:none;"> <thead><tr><th>Name</th><th>City</th></tr></thead> <tbody id="accountsTableBody"></tbody> </table>
 <div id="errorMessage"></div>
 <div id="message"></div>
</body>
</html>


If you are already logged in to your browser with CRM credentials then automatically it reads user token from your local browser and "Logout" button will appear other wise "Login" button will appear.

Once you click on "Retrieve Accounts" then it will display as below.




No comments:

Post a Comment

How to Trigger a Microsoft Flow from a Custom Button in Dynamics 365

  When using Microsoft Flow the out-of-the-box button is nested under the ‘Flow’ section and is not easy to find nor is it customizable. Tri...