Views:

Reference link :

https://api.cpm.account.microsoft-int.com/swagger/#/

Situation :

  • When a new Contact record in created in Microsoft dynamic CRM the email address should go to CPM system.
  • When new Email is created/send we need to validate the To email address field in CPM system. If it is valid then bind the unsubscribe link in email body.

Challenges :

  • Plugin does not support third party dll’s such as Newtonsoft.dll for json as the API request & response are in json format.
  • Plugin does not support Microsoft.IdentityModel.Clients.ActiveDirectory.dll still it is a Microsoft dll as this dll is required for the API request . It throws an exception on runtime if we add a reference in project.
  • Not able to figure out Resource in configuration as highlighted below in configuration image.

Requirements : 

  • On create of Contact record in CRM the contact email address push into CPM system and should check if the record is created from Portal.
  • Email Address validation & bind unsubscribe link in email body.

Solution :

Since this dll throws an run time exception we used the Httpwebrequest method to get the Access Token by passing the below configuration as shown in screenshot:

1) Getting the Access Token

To connect to CPM system first we need to get the access token from the API https://login.microsoftonline.com/{TenantId}/oauth2/token. Below is the code to get the access token by using the HttpRequestMessage method.

string loginUrl = $"https://login.microsoftonline.com/{TenantId}/oauth2/token";

                clientSecret = System.Uri.EscapeDataString(clientSecret);

                HttpClient client = new HttpClient();

                string postData = $"client_id={ClientId}&client_secret={clientSecret}&resource={Resource}&grant_type=client_credentials";

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, loginUrl);

                request.Content = new StringContent(postData);

                request.Content.Headers.Remove("Content-Type");

                request.Content.Headers.TryAddWithoutValidation("Content-Type", $"application/x-www-form-urlencoded");

                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

                var responseMessage = await client.SendAsync(request);

                var jsonResponseString = await responseMessage.Content.ReadAsStringAsync();

                var jsonContent = jsonResponseString.Deserialize<Dictionary<string, string>>();

                accessToken = jsonContent["access_token"];

2) Pushing Contact email address to CPM system.

After getting the access token we can pass this access token to the CPM Api https://api.cpm.account.microsoft-int.com/api/EmailContacts that will push the contact email address to the CPM system.

API Request:

EmailContactPoint emailContactPoint = new EmailContactPoint()

                    {

                        email = targetEntity.GetAttributeValue<string>("emailaddress1"),

                        country = "US",                                                 

                        topicSettings =  new List<ContactPointTopicSetting>(),

                    };

                    emailContactPoint.topicSettings.Add(new ContactPointTopicSetting

                    {

                        TopicId = new Guid("00000000-0000-0000-0000-000000000001"),                                          //Topic ID for which this permission was collected

                        CultureName = CultureInfo.CurrentCulture.ToString(),            //Specify a culture supported by the topic. E.g en-US, fr-FR, fr-CA etc. Communication with the user will be based on this culture;

                        LastSourceSetDate = DateTime.UtcNow,                            //The actual time at which this permission was collected. Could be in the past..

                        OriginalSource = "MSTAPlugin",                            //Name of this application that collected the consent. Saved for auditing purposes.

                        State = ContactPointTopicSettingState.OptInExplicit             //The permission

                    });

             //cpm api response

      EmailContactPoint updatedContactPoint = cpmClient.PatchEmailContactPoint(emailContactPoint, config, accessToken).Result;

             public async Task<EmailContactPoint> PatchEmailContactPoint(EmailContactPoint contactToPatch, PluginConfig config, string accessToken)

               {

                     var reqMessage = new HttpRequestMessage(new HttpMethod("PATCH"), "api/EmailContacts");

                      reqMessage.Content = new StringContent(contactToPatch.Serialize());

                     reqMessage.Content.Headers.ContentType = new Headers.MediaTypeHeaderValue("application/json");

                      return await MakeRequestAndParseResponse<EmailContactPoint>(reqMessage, config, accessToken);

        }

private async Task<T> MakeRequestAndParseResponse<T>(HttpRequestMessage reqMessage, PluginConfig config,string accessToken)

              {

                    reqMessage.Headers.Authorization = new Headers.AuthenticationHeaderValue("Bearer", accessToken);

              HttpResponseMessage response = await httpClient.SendAsync(reqMessage);

                     await ValidateResponse(response);

                    if (typeof(T) != typeof(object))

                    {

                string responseAsJson = await response.Content.ReadAsStringAsync();

                       using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(responseAsJson)))

                       {

                          // Deserialization from JSON 

                           DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

                    T responseObj = (T)deserializer.ReadObject(ms);

                           return responseObj;

                      }

                    }

                    else

                    {

                           return default(T);

                    }

        }

API response:   

 {

                              "email": "nb@iotap.com",

                      "country": "US",

                      "topicSettings": [

                                         {

       "cultureName": "en-US",

       "lastSourceSetDate": "2019-06-28T08:59:52.6750524Z",

       "originalSource": "SampleCPMProject",

       "state": "optInExplicit",

       "topicId": "00000000-0000-0000-0000-000000000001",

       "isVerified": true   

                                         }

        ]

               }

3) Validating email address in CPM system and getting the unsubscribe link from the CPM system

    API Request:

EmailContactabilitiesRequest request = new EmailContactabilitiesRequest()

                    {

                        TargetedTopicId = new Guid("00000000-0000-0000-0000-000000000001"),                                 //Topic Id for which you want to contact customers

                        UnsubscribeUrlRequired = true,

                        ContactPoints = new List<string>(),

                    };

                    foreach (string emailAddress in emails)

                    {

                        request.ContactPoints.Add(emailAddress);

                    }

                    JarvisCPMClient cpmClient = new JarvisCPMClient();

                  //CPM api response

     EmailContactabilitiesResponse result = cpmClient.GetEmailContactability(request, config, accessToken).Result;

public async Task<EmailContactabilitiesResponse> GetEmailContactability(EmailContactabilitiesRequest request, PluginConfig config, string accessToken)

               {

               var reqMessage = new HttpRequestMessage(HttpMethod.Post, "api/EmailContactabilities");

               reqMessage.Content = new StringContent(request.Serialize());

               reqMessage.Content.Headers.ContentType = new Headers.MediaTypeHeaderValue("application/json");

               return await MakeRequestAndParseResponse<EmailContactabilitiesResponse>(reqMessage,config,accessToken);

       }

private async Task<T> MakeRequestAndParseResponse<T>(HttpRequestMessage reqMessage, PluginConfig config,string accessToken)

              {

                    reqMessage.Headers.Authorization = new Headers.AuthenticationHeaderValue("Bearer", accessToken);

              HttpResponseMessage response = await httpClient.SendAsync(reqMessage);

                     await ValidateResponse(response);

                    if (typeof(T) != typeof(object))

                    {

                string responseAsJson = await response.Content.ReadAsStringAsync();

                       using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(responseAsJson)))

                       {

                          // Deserialization from JSON 

                           DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

                    T responseObj = (T)deserializer.ReadObject(ms);

                           return responseObj;

                      }

                    }

                    else

                    {

                           return default(T);

                    }

        }

API response:    

{

                "contacts": [

                                {

                                "email": "nb@iotap.com",

                                "canContact": true,

                                "unsubscribeUrl": "https://account.microsoft-int.com/profile/unsubscribe?CTID=0&ECID=Lfqg2DXoxMShzmVTr72%2FKg%3D%3D&K=8fd6fc11-2f81-44ef-8886-aeb7bbca5862&CMID=null&D=637037931174166928&PID=18000&TID=00000000-0000-0000-0000-000000000001",

                               "cultureName": "en-US"

                               },

                              {

         "email": "test@iotap.com",

                               "canContact": false,

                               "unsubscribeUrl": null,

                               "cultureName": null

                              }

                           ],

                          "targetedTopicId": "00000000-0000-0000-0000-000000000001"

              }

Conclusion :  

If we want to implement webrequest in plugin then we can use HttpRequestMethod.

There is no need of Microsoft.IdentityModel.Clients.ActiveDirectory.dll as this dll throws an exception at runtime.