Dynamics 365 Online S2S Authentication - Full Explain

Server-to-Server (S2S) authentication (only support Dynamics 365 online) was great, it use ClientId/SecretKey to authentication (instead use UserName/Password) and it use without Dynamics 365 license.

But everybody have problem when use CllientId/SecretKey, the main problem is HTTP Error 401 - Unauthorized: Access is denied

I headache this problem more than 3 days, and now, I succeed authentication with ClientId/SecretKey.

This post I will fully explain you how I can achieve it.

[Read More]

Please, don't hard code

When building hyperlinks to CRM in SSRS reports, please don’t hard code

  • Wrong: hard coding your CRM URL. Do not set your URL to “https://crmserver/….” If you do this use the hyperlink will only work in one environment and will have to be rewritten to work in another environment.
  • Right: Use the CRM_URL parameter in your report. This makes your links will work in all environments, even when offline.
    Parameters!CRM_URL
  • Wrong: Using OTC (ObjectTypeCode) in your hyperlink expression. ObjectTypeCode never changes for System entities, but for custom entity ObjectTypeCode will change when customization is imported into a new environment.
    ="OTC=1&ID={“ & Fields!accountid.Value.ToString() & ”}”
  • Right: Use the logical entity name instead of ObjectTypeCode.
    ="LogicalName=account&ID={“ & Fields!accountid.Value.ToString() & ”}”

Get Sql ConnectionString from CRM server code

Sometime, your business logic need access direct SQL Server, and you want to know the ConnectionString of CRM Database.

This code will help you get Sql ConnectionString from CRM Plugin/Custom Action/Custom Workflow (before that I saved the ConnectionString to the custom Options entity)

public void Execute(IServiceProvider serviceProvider)
{
    var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    var platformContext = context.GetType().InvokeMember("PlatformContext", BindingFlags.GetProperty, null, context, null);
    var transaction = (SqlTransaction)platformContext.GetType().InvokeMember("SqlTransaction", BindingFlags.GetProperty, null, platformContext, null);
    throw new InvalidPluginExecutionException(transaction.Connection.ConnectionString);
}
  • Remember to add reference System.Data.dll to your project

Limitation

  • CRM On-Premises only
  • Plugin/Custom Action/Custom Workflow when register the option Isolation Mode should selected None
  • Access SQL code should out side the Plugin/Custom Action/Custom Workflow pipe line transaction. (E.g: use at Pre-Validation)

Actual project experience

  • Requirement: End user want change exchange rate at the end of month after a lot of records created/locked on this month with current temporary exchange rate.
  • Analysis: You cannot use the SDK code because a lot of records locked by CRM
  • Solution:
    • Create a custom action, get SQL ConnectionString, and then use the ConnectionString to update records
    • Create a custom ribbon button, then call custom action to update data.