Use CrmServiceClient to execute web request against Web API – Dynamics 365


In the previous post we saw how to use CrmServiceClient to connect to CDS using Authentication Type – OAuth and execute web request using Organization.svc service

https://nishantrana.me/2020/11/09/sample-code-to-connect-to-cds-dynamics-365-ce-using-oauth/

Here we will extend the same example to execute web request using Web API.

  • Create the contact record with first name and last name populated

using Microsoft.Xrm.Tooling.Connector;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;

namespace SampleConsoleApp
{
class Program
{
static void Main(string[] args)
{
string ConnectionString = "AuthType = OAuth; " +
"Username = [username]@[domain].onmicrosoft.com;" +
"Password = [password]; " +
"Url = https://[orgname].crm.dynamics.com;" +
"AppId=51f81489-12ee-4a9e-aaae-a2591f45987d;" +
"RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97;" +
"LoginPrompt=Auto";

CrmServiceClient svc = new CrmServiceClient(ConnectionString);

// specify OData Headers
Dictionary<string, List<string>> odataHeaders = new Dictionary<string, List<string>>
{
{ "Accept", new List<string>() { "application/json" } },
{ "OData-MaxVersion", new List<string>() { "4.0" } },
{ "OData-Version", new List<string>() { "4.0" } }
};

if (svc.IsReady)
{
// create a contact record with firstname and lastname populated
dynamic contact = new JObject();
contact.firstname = "Meeska";
contact.lastname = "Mooska";
string jsonContact = Newtonsoft.Json.JsonConvert.SerializeObject(contact);

// create the contact record
// Parameters - HttpMethod, QueryString, Body, Customer Headers, Content Type
HttpResponseMessage httpResponse = svc.ExecuteCrmWebRequest(
HttpMethod.Post,
"contacts",
jsonContact,
odataHeaders,
"application/json");

if (httpResponse.IsSuccessStatusCode)
{
var contactUri = httpResponse.Headers.GetValues("OData-EntityId").FirstOrDefault();
Console.WriteLine("Contact URI: {0}", contactUri);
}
else
{
Console.WriteLine(httpResponse.ReasonPhrase);
}
}
}
}
}

  • Retrieve first name and last name for all the contact

// retrieve first name and last name of all the contact records 
HttpResponseMessage httpResponse = svc.ExecuteCrmWebRequest(
HttpMethod.Get,
"contacts?$select=firstname,lastname",
string.Empty,
odataHeaders,
"application/json");

 

Get the details here – ExecuteCrmWebRequest

Hope it helps..

Process Optimization – Dynamics 365 CE / CRM / CDS SSIS Integration toolkit – KingswaySoft


Process Optimizations is a new feature added in the CDS / CRM Destination Component of KingswaySoft’s SSIS Integration Toolkit as part of November 2020 Release.

Check other posts on SSIS and Dynamics 365

https://nishantrana.me/2020/10/16/ssis-kingswaysoft-and-dynamics-365/

These options if enabled, will turn off or disable plugin, workflow, entity auditing during pre-execution temporarily, during the writing process, and will revert the changes to the original state after successful execution.

  • Tentatively Disable Relevant Plugins (if any)
  • Tentatively Disable Relevant Workflows (if any)
  • Tentatively Disable Relevant Auditing (if any)

Let us take a simple example to see it in action.

Here we have a simple data flow that creates contact records inside CDS using Data Spawner.

https://nishantrana.me/2020/05/26/using-data-spawner-component-ssis-to-generate-sample-data-in-dynamics-365/

Let us run the package and see the status of the plugin, workflow, and audit with regards to the contact entity.

As expected, we do not see any Audit records created for contact records creation.

We see an event where Audit is disabled and then enabled later for the contact entity, during the duration of package running and after its successful completion.

We can also see our workflow in status – Draft

In the case of Plugin, we didn’t see the step being disabled and it was still being triggered

As per the documentation –

Get the toolkit here

https://www.kingswaysoft.com/products/ssis-integration-toolkit-for-microsoft-dynamics-365

Hope it helps..

Embedding Canvas App in an Iframe inside Dynamics 365


Canvas App can be easily embedded in a web site using the Iframe.

Say e.g. we have the following Canvas App to be embedded inside Dashboard in Dynamics 365

Save the app and navigate to Details

We can copy the Web link or App ID.

The URL Format –

https://apps.powerapps.com/play/[appId]

The other parameter that can be used are

source, tenantid, screencolor and any additional parameters

e.g.

https://apps.powerapps.com/play/[appId]?source=iframe&screenColor=rgba(120,110,55,1)&param1=value&param2=value 2

  • Here we have embedded it inside an Iframe component within the Dashboard

Publish the change and navigate to the Dashboard, we can see our Canvas App.

If the application is using Azure Active Directory-based authentication, the user will not be asked to sign-in again, else the user will be asked to Sign-in and will be able to access the app if it is shared with them.

Here we have embedded it inside an ASP.NET page, and we are asked to Sign-in.

After successful sign-in

Get all the details here –

https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/embed-apps-dev

Hope it help..

System.FormatException: Input string was not in a correct format exception while registering Plugin in Dynamics 365


We might get the below error while trying to register a plugin.




Cause

The plugin project was referring the .NET Framework 4.7.2


And the latest version of Microsoft.CrmSdk.CoreAssemblies – (Sept 29, 2020)

2020-11-10_19-33-39

Resolution –

Changing it to 4.6.2 fixed it.



Details-

Unhandled Exception: System.ServiceModel.FaultException

An unexpected error occurred.

Server stack trace:

at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)

at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.Create(Entity entity)

at Xrm.Sdk.PluginRegistration.Forms.PluginRegistrationForm.btnRegister_Click(Object sender, EventArgs e)

Detail:

<OrganizationServiceFault xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts&#8221; xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”&gt;

<ActivityId>6906e911-4a07-487a-bdf0-ad52914b9f14</ActivityId>

<ErrorCode>-2147220970</ErrorCode>

<ErrorDetails xmlns:a=”http://schemas.datacontract.org/2004/07/System.Collections.Generic”&gt;

<KeyValuePairOfstringanyType>

<a:key>ApiExceptionSourceKey</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>Plugin/Microsoft.Crm.ObjectModel.PluginAssemblyService</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiOriginalExceptionKey</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>Microsoft.Crm.CrmException: An unexpected error occurred. —&gt; System.FormatException: Input string was not in a correct format.

at System.Text.StringBuilder.FormatError()

at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)

at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)

at System.String.Format(IFormatProvider provider, String format, Object arg0, Object arg1)

at Microsoft.Crm.ObjectModel.TargetFrameworkVersionValidator.ValidateInternal()

at Microsoft.Crm.ObjectModel.PluginValidatorBase.Validate()

at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.ValidateAssemblyMetadata(ExecutionContext context, IBusinessEntity pluginAssembly, CrmPluginAssemblyMetadata assemblyMetadata)

at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.VerifyRegistrationAbility(IBusinessEntity pluginAssembly, Boolean createCall, ExecutionContext context, CrmPluginAssemblyMetadata assemblyMetadata)

at Microsoft.Crm.ObjectModel.PluginAssemblyServiceInternal`1.ValidateOperation(String operationName, IBusinessEntity entity, ExecutionContext context)

at Microsoft.Crm.ObjectModel.SdkEntityServiceBase.CreateInternal(IBusinessEntity entity, ExecutionContext context, Boolean verifyAction)

— End of inner exception stack trace —

at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)

at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action, PipelineExecutionContext context)

at Microsoft.Crm.Extensibility.Pipeline.&lt;&gt;c__DisplayClass5_0.&lt;RunStep&gt;b__0()</a:value>

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiStepKey</a:key>

<a:value i:type=”b:guid” xmlns:b=”http://schemas.microsoft.com/2003/10/Serialization/”>3ecabb1b-ea3e-db11-86a7-000a3a5473e8</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiDepthKey</a:key>

<a:value i:type=”b:int” xmlns:b=”http://www.w3.org/2001/XMLSchema”>1</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiActivityIdKey</a:key>

<a:value i:type=”b:guid” xmlns:b=”http://schemas.microsoft.com/2003/10/Serialization/”>6906e911-4a07-487a-bdf0-ad52914b9f14</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiPluginSolutionNameKey</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>System</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiStepSolutionNameKey</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>System</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiExceptionCategory</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>SystemFailure</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiExceptionMesageName</a:key>

<a:value i:type=”b:string” xmlns:b=”http://www.w3.org/2001/XMLSchema”>UnExpected</a:value&gt;

</KeyValuePairOfstringanyType>

<KeyValuePairOfstringanyType>

<a:key>ApiExceptionHttpStatusCode</a:key>

<a:value i:type=”b:int” xmlns:b=”http://www.w3.org/2001/XMLSchema”>400</a:value&gt;

</KeyValuePairOfstringanyType>

</ErrorDetails>

Hope it helps..



 

Changes in CDS / CRM Destination Component – SSIS Integration Toolkit for Dynamics 365


With version 20.2 November 2020 release, there have few updates added to the KingwaySoft’s CDS/CRM Destination Component, few are changes in the label and others are metadata changes, that one should be aware of before updating.

Check Post on SSIS and Dynamics 365

https://nishantrana.me/2020/10/16/ssis-kingswaysoft-and-dynamics-365/

  • Label changes.

Version 20.1 –

Version 20.2 –

  • CrmRecordId renamed to SavedRecordId

Version 20.1 –

Version 20.2 –

  • CrmErrorMessage renamed to ErrorMessage

Version 20.1 –

Version 20.2 –

Thus, any package saved with the new version will not work with the older version, and it is recommended to take full back up of the package before updating to the new version.

Hope it helps..

Sample code to connect to CDS / Dynamics 365 / CE using OAuth


Sample code for quick reference for connecting to CDS through a console application using OAuth

Add the NuGet package for Microsoft.CrmSdk.XrmTooling.CoreAssembly in the project.

Xrm.Tooling is the preferred way to connect to CDS, because of many benefits – we can define connection string, thread safety, support for X.509 certificate authentication, support for secure storage of sign-in credentials and reuse etc.

Note

Here we will be using the sample AppId and Redirect URI.

Sample Code- 


using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
using System;

namespace SampleConsoleApp
{
class Program
{
static void Main(string[] args)
{
string ConnectionString = "AuthType = OAuth; " +
"Username = [username]@[domain].onmicrosoft.com;" +
"Password = [password]; " +
"Url = https://[orgname].crm.dynamics.com;" +
"AppId=51f81489-12ee-4a9e-aaae-a2591f45987d;" +
"RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97;" +
"LoginPrompt=Auto";

CrmServiceClient svc = new CrmServiceClient(ConnectionString);

if (svc.IsReady)
{
var myContact = new Entity("contact");
myContact.Attributes["lastname"] = "Test";
myContact.Attributes["firstname"] = "User1";
svc.Create(myContact);
}
}
}
}


For .NET Framework 4.5.2 – we need to explicitly specify Tls1.2 as the default protocol. 

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

https://nishantrana.me/2018/01/

.NET Framework 4.6.2 uses TLS 1.2 as the default protocol.

 

More details on – Connection string parameters.

Hope it helps..