Oct 19, 2017

Programmatically Share, Retrieve Shared Users and UnShare a Dynamics 365 record with a User OR Team

This is just to share some simple code snippets relates to sharing. This works well.

Sharing

using Microsoft.Crm.Sdk.Messages;

public static void ShareRecord(IOrganizationService OrganizationService, string entityName, Guid recordId, Guid UserId)
{
    EntityReference recordRef = new EntityReference(entityName, recordId);
    EntityReference User = new EntityReference(SystemUser.EntityLogicalName, UserId);

    //If its a team, Principal should be supplied with the team
    //EntityReference Team = new EntityReference(Team.EntityLogicalName, teamId);

    GrantAccessRequest grantAccessRequest = new GrantAccessRequest
    {
        PrincipalAccess = new PrincipalAccess
        {
            AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess | AccessRights.AppendToAccess | AccessRights.,
            Principal = User
            //Principal = Team
        },
        Target = recordRef
    };
    OrganizationService.Execute(grantAccessRequest);
}

Its great that VS intellisense would help you identify which Access Right you can set.


Retrieve user who has been shared with
public static void RetrieveSharedUsers(IOrganizationService OrganizationService, EntityReference entityRef)
{
    var accessRequest = new RetrieveSharedPrincipalsAndAccessRequest
    {
        Target = entityRef
    };
    var accessResponse = (RetrieveSharedPrincipalsAndAccessResponse)OrganizationService.Execute(accessRequest);
    foreach (var principalAccess in accessResponse.PrincipalAccesses)
    {
        // principalAccess.Principal.Id - User Id
    }
}

Revoke the Share (UnShare)
 public static void RevokeShareRecord(IOrganizationService OrganizationService, string TargetEntityName, Guid TargetId, Guid UserId)
 {
    EntityReference target = new EntityReference(TargetEntityName, TargetId);
    EntityReference User = new EntityReference(SystemUser.EntityLogicalName, UserId);

    RevokeAccessRequest revokeAccessRequest = new RevokeAccessRequest
    {
        Revokee = User,
        Target = target
    };
    OrganizationService.Execute(revokeAccessRequest);
}

Oct 11, 2017

Console App to Connect to Dynamics 365

One way of testing complex custom codes for Dynamics 365 is executing them using a Console App. This post explains how to create a Console App that enables you to use early bound classes. This can come in handy when you need to test your complex Linq queries before implementing.

1. Once Create empty Console app we need to install below two NuGet Packages;
  • Microsoft.CrmSdk.CoreAssemblies
  • Microsoft.IdentityModel

2. Now Download and reference below Assemblies
  • Microsoft.IdentityModel.Clients.ActiveDirectory.dll
  • Microsoft.Xrm.Tooling.Connector.dll

3. Now create the early bound classes
For this Open the Command Prompt and go to Bin Folder of Dynamics 365 SDK. Then execute CrmSvcUtil.exe. Check given sample command line used for my scenario;

CrmSvcUtil.exe /url:https://xxxx.crm6.dynamics.com/XRMServices/2011/Organization.svc /out:Xrm.cs /username:xxxx@xxxx.onmicrosoft.com /password:xxxxx/namespace:TestConsoleDynamics365 /serviceContextName:TcServiceContext

4. Add the early bound Classes
Add a Class Library file to solution called Xrm.cs and copy relevant content from generated file in previous step. Your solution will now look like this in terms of file structure.


5. Now Open the Program.cs file and do the code as below. This sample consist of one method that uses Linq query to retrieve account name from Id.

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

namespace TestConsoleDynamics365
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Conncetion to Dynamics 365");
            String connectionString = GetServiceConfiguration();

            Console.WriteLine("Conncetion string : " + connectionString);
            Console.WriteLine("Press Enter to move on..");
            Console.ReadLine();

            CrmServiceClient conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connectionString);

            IOrganizationService _orgService = (IOrganizationService)conn.OrganizationWebProxyClient != null ? (IOrganizationService)conn.OrganizationWebProxyClient : (IOrganizationService)conn.OrganizationServiceProxy;

            //TEST CODE
            Account acc = RetriveAccountById(_orgService, new Guid("628B3A81-CA93-E711-814F-E0071B662BF1"));
            string AccountName = acc != null ? acc.Name : "Nothing Found";
            Console.WriteLine("Sample Account : " + AccountName);
            Console.ReadLine();
        }

        internal static Account RetriveAccountById(IOrganizationService service, Guid Id)
        {
            Account account = null;
            using (TcServiceContext serviceContext = new TcServiceContext(service))
            {
                account = (from c in serviceContext.CreateQuery<Account>()
                           where c.Id == Id
                           select c).FirstOrDefault();
            }
            return account;
        }

        private static string GetServiceConfiguration()
        {
            return "Url = https://xxxxxx.crm6.dynamics.com; Username=xxxx@xxxxx.onmicrosoft.com; Password=xxxxxx; authtype=Office365";
         }
    }
 }

6. Now Run and see. Here is my result;


Note:
My intention is to give simplest code only, though code can be improved according to best practices which I am not discussing here. Ex: storing connection string in the config file.

Oct 9, 2017

Synchronize Contacts to a Table Using Azure Logic Apps

I have suggested few ways of getting free Azure Subscriptions for Dynamics 365 developers through a post. Click here to read that.

Now though of jumping in to Azure Logic Apps, among many new Dynamics 365 + Azure technologies.

Azure Logic Apps come in handy in integrating Dynamics 365 with many third-party applications. Anyway, most fundamental requirement could be to synchronize an entity data with a SQL database. Below step-by-step guide is to illustrate how we can achieve this in a simple manner.

Let’s open a logic app in Azure. Click New, Select Web + Mobile and select Logic App.


 Now give a meaningful name to the Logic App and Create a Resource group or select existing one.


Then you will come to Logic App Designer with all kinds of Templates. Still I prefer to use a Blank Template for the sake of learning and flexibility. Click Blank Template and select Dynamics 365 as the Connector as below.


Within many triggers, select Dynamics 365 – When record is created or updated as the trigger.



Obviously, you need to provide your Dynamics 365 Organization and Entity interested in synchronizing. In my scenario, it’s Contact.


Now add the Condition which does the trick. In Dynamics 365, we have selected the trigger which tracks both Create and Update operations. You may notice we don’t have such single operation in SQL. Our approach is to check if Created on equals Modified On. If Condition satisfies, it’s a Create or else an Update.


Now add SQL server Insert row action if condition is satisfied and match the table fields with Dynamics 365 fields as below. I have selected only few fields here, but it’s essential to map Id column so Dynamics and SQL table record can be mapped for Update Operation.


Now add SQL server Update row action if condition is NOT satisfied and match the table fields with Dynamics 365 fields as below. You will notice we have extra field called Row id here which is nothing but the Primary Key. This is obviously necessary for Updating.


Now run the logic App and try the operation.

I created Contact record for Mark Wilkinson, and I got below record created through Logic App. App identified this as a Create operation since both Created On and Modified On values are same.


Then I changed the Description field and found it’s correctly updating the record as below.


This is just simple explanation, but this is evident Logic Apps can be used to synchronize Dynamics 365 data with SQL tables easily.

Oct 4, 2017

Validate Next Stage button of Business Process Flow

In Business Process Flows in Dynamics 365, we can proceed to next stage by clicking Next Stage button, if all the required fields in the current stage is filled. This is a straight forward validation. Anyway, we may need to do bit more tricky validations through JavaScript.

Let’s see the approach for adding a client script for this event. Please check below code snippet. As you may notice Stage Name and Direction are giving us most needed values to identify when we need to execute our logic.

function onLoad()
{
    Xrm.Page.data.process.addOnStageChange(OnStageProgress);
}

function OnStageProgress(executionContext)
{
    var stageName = Xrm.Page.data.process.getActiveStage().getName();
    var direction = executionContext.getEventArgs().getDirection();
    alert(stageName);
    alert(direction); //Values are Next OR Previous
}

Consider this scenario for an example. I need to move to next stage which is Complete stage if either of Description or Company Name is filled. Let’s extend the logic for that;

function OnStageProgress(executionContext) {
    var stageName = Xrm.Page.data.process.getActiveStage().getName();
    var direction = executionContext.getEventArgs().getDirection();

    var description = Xrm.Page.getAttribute('description').getValue();
    var company = Xrm.Page.getAttribute('parentcustomerid').getValue();

    if ((direction == 'Next') && (stageName == 'Complete'))
    {
    if ((description == null) && (company == null))
    {
        Xrm.Page.data.process.movePrevious(function () {
        Xrm.Page.ui.setFormNotification('Either Description OR Company is required', 'ERROR');
        });
    }
    }
}

Here we get the error message as expected.


Anyway, we need to add Xrm.Page.ui.clearFormNotification(); in onSave event so notices will be cleared when filling either of fields.