Advertisements

Archive

Archive for the ‘Dynamics 365’ Category

Web API Helper Code Compilation Error

September 18, 2018 Leave a comment

I was creating a console application to connect to Dynamics 365 Web API, and downloaded “Microsoft.CrmSdk.WebApi.Samples.HelperCode” NuGet package.

Compilation Error_1

I got “AcquireToken method is no longer available” compilation error, when I build the project

Compilation Error

Reason & Fix:

  • We have to use UserPasswordCredential class in ADAL v3.
  • Below is the code snippet

var credentials = new UserPasswordCredential(userName, password);
var context = new AuthenticationContext(authorityUri);
authResult = context.AcquireTokenAsync(serviceUrl, applicationId, credentials).Result;

Refer my previous article for step by step to connect to Dynamics 365 Web API.

🙂

Advertisements

[Fix] AADSTS65001: The user or administrator has not consented to use the application

September 18, 2018 Leave a comment

I was getting below exception when I was trying to connect to D365 Web API from console.

AAD_Access_2

Reason:

  • Issue was the Application registered on ‘Azure Active Directory’ was not granted the Permission

Fix:

  • Connect to the Azure Active Directory admin center,  using O365 credentials.
  • Select the ‘Application’ from the ‘Azure Active Directory -> App registrations’
  • Click on ‘Settings’ -> Required Permissions -> Click on ‘Grant permissions‘ button

AAD_Access_1

Refer my previous article on how to register application and connect to D365 Web API

🙂

[Code Snippet] Authenticate and Perform Operations using D365 Web API and C#

September 18, 2018 3 comments

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.

WebAPI_Snippet2

  • From the “Azure Active Directory admin center’, select ‘App registrations’ -> New application registration

WebAPI_Snippet3

  • 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.

WebAPI_Snippet4

  • Click ‘Create’ to complete the App creation
  • Post creation, open the App and copy the ‘Application ID’ which you need in Console application.

WebAPI_Snippet5

  • Click on ‘Settings’ -> Required Permissions -> Add ‘Dynamics CRM Online’ -> Enable the permission as below

WebAPI_Snippet6

  • Finally, select the App, click on ‘Endpoints’ and copy ‘OAuth 2.0 Authorization Endpoint‘ which you would need in Console Application.

WebAPI_Snippet7

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

WebAPI_Snippet8

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();
}
}

WebAPI_Snippet1

  • 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

September 17, 2018 1 comment

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
    1. 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.
    2. If your Dynamics 365 is On-premise, you can authenticate Web API by passing User’s network credentials.
    3. If your Dynamics 365 is Online or IFD, you must use OAuth to connect.
  • 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:

WebAPI_Connect.PNG

🙂

Categories: CRM, Dynamics 365 Tags: , ,

Dynamics 365 – Different types of User Accounts and License consumption

Other day I was asked a question “What are the options to create/migrate users in Dynamics 365 application with no license consumption”

The options are

  • Create a User of type ‘Stub User’ which does not consume license
  • Sync a User from O365 to Dynamics 365 and remove the license later. This approach deactivates the User in D365 and free up the license.
  • Create an Application User
  • Create an Administrative User account
  • Create a Non-Interactive User account

To know different options is crucial, especially, when you are migrating the Users from legacy systems and the Users are not expected to access the D365 application which should not cost any licenses.

In this article, I am going explain the different type of Users and how they consume the licenses.

Administrative User Account:

  • An Administrative user is a user, who has access to the Settings and Administration features but has no access to any of the customer engagement functionality.
  • Since the administrative user does not have access to customer data and any of the customer engagement functionalities, it does not require a Dynamics 365 (online) license.
  • To create an ‘Administrative User’
    • Create a User in Office 365; (Admin Center -> Users -> Active users -> Add a user)
  • User2
    • Assign a Dynamics 365 license under ‘Product licenses’ tab.
  • User3
    • Go to D365 application and open the User record
    • On the User form, under ‘Administration’ tab, ‘Client Access License (CAL) Information’ section and select “Administrative” for Access Mode.
  • User1
    • Final step is, remove the Dynamics 365 license of the User from Office 365, so that you can free the license and still the User can login to the application as ‘Administrative’

Non-interactive User Account:

  • Non-interactive user is not a physical User and It is used for programmatic access to and from Dynamics 365 between applications.
  • Non-interactive user let applications (i.e., Consoles, SSIS packages or ERP connector etc.) authenticate and access Dynamics 365 (online), without requiring a Dynamics 365 (online) license.
  • Creation of Non-interactive user account is same as Administrative User Account, except setting the Access Mode to ‘Non-interactive’
  • There is a limit of five non-interactive user accounts

Application User Account:

  • ‘Application User’ is used while establishing server-to-server (S2S) authentication
  • ‘Application User’ with conjunction of Azure Active Directory (Azure AD) will establish S2S authentication.
  • ‘Application User’ does not consume license.
  • Application users are created with a non-interactive user account, however they are not counted towards the 5 non-interactive user accounts limit.

Stub User:

  • Stub user cannot log in, cannot be enabled, and cannot be synchronized to Office 365 and will not consume license.
  • Stub Users are designed for records that have been imported that refer to this user but the user does not exist in Dynamics 365 (online).
  • Stub users are user records that are created in Dynamics 365 using Data Import or using the Create or Create Requests methods of the SDK.

Licensed User:

  • Licensed user is an User whom gets created in O365 with license and synced to D365.
  • Licensed users must be assigned at least one Dynamics 365 security role to access Dynamics 365 (online).
  • The service does not allow access to users who do not have at least one security role.
  • Removing all security roles from the user prevents the user from signing into and accessing Dynamics 365 (online). However, it doesn’t remove the license from the user.

Refer article for more details.

🙂

 

Dynamics 365 – How to get App URL

Using PowerApps, we can create custom business apps comprised of components such as entities, dashboards, forms, views, charts, and business processes.

Its convenient way to package and provide the components which are matter to the Users.

Lets take a scenario to understand this better

  • A sales company has users having ‘Sales Persons’ and ‘Sales Managers’ roles
  • Sales Persons are intend to access only Accounts & Contacts
  • All I need to do is create an App with those entities and grant App access to ‘Sales Person’ security role. Refer my previous article.
  • Share the ‘App’ URL to the Sales Persons

Below are the steps to get the ‘App’ URL:

  • Open the Dynamics Application
  • Navigate to Settings -> My Apps -> Published Apps -> {Your App} -> Click on and then click ‘Manage Roles’

App URL

  • Expand “App URL Suffix” tab
  • Click on ‘Copy’ icon to copy the URL

App URL-2

  • Share the URL to users and when they access,  they will directly taken to the ‘App’

App URL-3

What is App URL Suffix

  • The app URL is automatically populated based on the App name that you specify.
    • In my example, my ‘App’ name is ‘HelloWorld’ and hence ‘App URL Suffix’ is set to ‘HelloWorld’
  • The app URL must be unique.
  • Below are the URL syntax

🙂

Categories: Dynamics 365 Tags: ,

D365 – Unified Interface – Create an App and Grant App access to a Security Role

August 2, 2018 1 comment

In this article, I am going to provide steps to create new App and how to grant the App access to a particular Security Role.

Prerequisite to create App:

User must have the following privileges to create App:

  • Create, Read, and Write privileges for the “App” entity
  • Read and Write privileges for the “Customizations” entity
  • Read privileges for the “Solution” entity

Steps to create App:

  • From your Dynamics Application, go to Settings -> My Apps -> Create new App
  • You will be redirected to “Create a New App” window
  • In this example, I am going to use “Existing Solution” to add the App (Note: If any site map is available for the selected solution, the Select Sitemap drop-down list will appear when you clicked ‘Next’.)
  • Select the “Client” (Web/Unified Interface)
    • Web: This is the classic Dynamics 365 web browser client.
    • Unified Interface: This is the newer responsive web browser client that has a similar interface across PC and mobile devices.

App1

  • Click ‘Next’ to select the ‘Solution’
    • Note: ‘Next’ button will be available only if you select ‘Use existing solution to create the App’

App2

  • Click ‘Done’

Add components to the ‘App”:

  • Next is add the components (i.e., Entities, Dashboard, etc..) to ‘App’
  • In this example, I am adding ‘Account’, ‘Contact’ entities to the Sitemap

App3

  • Once you add all components, click on ‘Save’ and then ‘Publish’

Publish The ‘App’:

  • Once you create the App, next step is to ‘Publish’ so that it will be available for the respective users.
  • Go to Settings -> My Apps -> Apps Being Edited
  • Pick your App and click on and then click ‘Publish’

App4

  • Post ‘Publish’, App will be available under ‘Published Apps’ section

Grant App access to a Security Role:

Lets grant the access to Users who has ‘Sales Person’ security role.

  • Select your App from Settings -> My Apps -> Published Apps
  • Click on and then click ‘Manage Roles’

App5

  • Under the ‘Roles’ section, pick the ‘Security Role’ which you would like to grant App access to.

App6

Troubleshooting steps If App is not accessible:

  • Once you grant App access to a security role and if the App is not accessible, make sure the ‘Security Role’ has ‘Read’ privilege on ‘App‘ entity

App7

Package/Delete an app:

  • ‘App’ can be added as Solution component and can be moved between Dynamics applications
  • To delete the ‘App’, navigate to Solution -> Components ->Apps, select the App and click ‘Delete’

App8

🙂