Tuesday, January 11, 2022

How to send email to all users who are following a case.


Refer here: To know about Follow Functionality in Dynamics 365 CRM

 

This blog describes the functionality where all users will receive an email notification for case bring followed by them is updated. To demonstrate this we are considering the case origin field on the Case entity.

Through this, the user will know about any actions being performed on the case instead of manually looking into it. 

Users can also unfollow the case from receiving email notifications whenever they wish to. 



Plugin Code:

namespace Crm.Plugins

{

public class EmailToUsersForCaseFollowed: IPlugin

{

public void Execute(IServiceProvider serviceProvider)

{

    IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

    IOrganizationServiceFactory serviceFactory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

    ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

 

    Entity targetentity = (Entity)context.InputParameters["Target"];

 

    EntityCollection users = GetUsersWhoFollowCase(service, targetentity.Id);

    if (users.Entities.Count > 0)

    {

        EntityCollection toPartyCollection = new EntityCollection();

        foreach (Entity user in users.Entities)

        {

            Guid userId = user.GetAttributeValue<EntityReference>("ownerid").Id;

 

            Entity toParty = new Entity("activityparty");

            toParty["partyid"] = new EntityReference("systemuser", userId);

            toPartyCollection.Entities.Add(toParty);

        }

        if (toPartyCollection.Entities.Count > 0)

        {

            EntityReference caseref = new EntityReference("incident", targetentity.Id);

          

            //Please change GUID for SystemUserID to send an email

            EntityReference from = new EntityReference("systemuser", new Guid("319c52a2-fc46-ec11-8c60-000d3af29037"));

          

            Entity fromParty = new Entity("activityparty");

            fromParty.Attributes.Add("partyid", from);

         

            EntityCollection fromPartyCollection = new EntityCollection();

            fromPartyCollection.EntityName = "systemuser";

            fromPartyCollection.Entities.Add(fromParty);

 

            Entity email = new Entity("email");

            email.Attributes.Add("regardingobjectid", caseref);

            email.Attributes.Add("subject", "Case Origin is being Updated");

            email.Attributes.Add("description""your detail description about case updated goes here");

            email.Attributes.Add("from", fromPartyCollection);

            email.Attributes.Add("to", toPartyCollection);

            Guid emailID = service.Create(email);

 

            SendEmailRequest reqSendEmail = new SendEmailRequest();

            reqSendEmail.EmailId = emailID;

            reqSendEmail.TrackingToken = "";

            reqSendEmail.IssueSend = true;

            SendEmailResponse res = (SendEmailResponse)service.Execute(reqSendEmail);

        }

    }

}

 

public EntityCollection GetUsersWhoFollowCase(IOrganizationService orgService, Guid caseId)

  {

    EntityCollection userEntityCollection = new EntityCollection();

    QueryExpression caseQuery = new QueryExpression("postfollow")

    {

        NoLock = true,

        ColumnSet = new ColumnSet("regardingobjectid", "ownerid")

    };

    caseQuery.Criteria.AddCondition("regardingobjectid", ConditionOperator.Equal, caseId);

 

 

    userEntityCollection = orgService.RetrieveMultiple(caseQuery);

    return userEntityCollection;

  } 

 }

}


Register the Plugin on 

  • Update of Case Entity 
  • with Filtering Attributes caseorigincode. 



You can Check the Timeline for the email received by the user whenever the records are updated. 

























Follow Functionality in Dynamics 365 CRM

In this blog, we will learn about the "Follow" functionality in Dynamics CRM.

  • The Follow functionality helps to track various activities performed for a record or multiple records.
  • We can follow records for out-of-box entities like leads, accounts, and contacts and get to see views like Leads I follow, Accounts I follow or Contacts I follow
  • For custom entities, we need to manually activate (configure) Follow functionality.


Let’s begin. We have a custom entity named “Student”

Navigate to Advance settings > Security > Activity Feeds Configuration.


Search the custom entity from the Post Configuration view. The status for the custom entity must be Inactive, you need to activate it.


To Activate the entity for Follow functionality, select the entity. Click on Activate Button as shown in the below screenshot.


You will get a confirmation box for activation. Click on Activate.


In order to replicate the same in the form, we need to Publish the Customization.



Now navigate to the custom entity (Student in my scenario) and notice two new views added


Open any existing record. Click on 3 dots you will find a follow option now. 


You can now check

  • list of Students you follow from view Student I Follow
  • list of Students Followed by other users as well, from the option Students being Followed.



Troubleshooting the ‘I Follow’ functionality

If you do not get the Follow option try the following:

  • Make sure you publish the entity customization
  • Make sure that the user has sufficient privilege under his security role.




Hope this will resolve your issue.

Monday, December 27, 2021

Plugin in Dynamic 365 CRM


In this blog, we will get an overview of a plugin with a detailed step-by-step creation of a plugin with an example. 

Here, we will create a plugin that will trigger when the Lead is created and will create a follow-up task.

Connect to Dynamic 365 CRM from Console App using Azure Authentication

Why Plugin?

Plugins are custom code that attaches to CRM’s built-in event pipeline. This allows developers to extend the default behavior of CRM so we could design/develop it exactly as per the organizational needs.


Create a .NET project:

From Visual Studio, create a new Project. Add Class Library (.net Framework). Click on Next.


Now, give a relevant name for the project. Click on Create. This will create a new project with a class.



Right-click on the Project. Then click on Manage NuGet Package. Add the Microsoft.CrmSdk package. Click on Install.


Add the below Plugin Code:


using System;

using Microsoft.Xrm.Sdk;

 

namespace FollowupTaskPlugin

{

    public class Class1 : IPlugin

    {

        public void Execute(IServiceProvider serviceProvider)

        {

                // Obtain the execution context from the service provider.

                IPluginExecutionContext context = (IPluginExecutionContext)

                   serviceProvider.GetService(typeof(IPluginExecutionContext));

     

         if (context.InputParameters.Contains("Target") && context.InputParameters["Target"]is Entity) {

 

                    // Obtain the target entity from the input parameters.

                    Entity entity = (Entity)context.InputParameters["Target"];

                    try

                    {

 

                        // Create a task activity to follow up with the account customer in 7 days

                        Entity followup = new Entity("task");

                        followup["subject"] = "Send e-mail to the new User";

                        followup["description"] ="Follow up with the User";

                        followup["scheduledstart"] = DateTime.Now;

                        followup["scheduledend"] = DateTime.Now.AddDays(2);

                        followup["category"] = context.PrimaryEntityName;

 

                        if (context.OutputParameters.Contains("id"))

                        {

                            Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());

                            string regardingobjectidType = "lead";

                            followup["regardingobjectid"] =

                               new EntityReference(regardingobjectidType, regardingobjectid);

                        }

 

                        IOrganizationServiceFactory serviceFactory =

                           (IOrganizationServiceFactory)serviceProvider.GetService

                           (typeof(IOrganizationServiceFactory));

                        IOrganizationService service =

                           serviceFactory.CreateOrganizationService(context.UserId);

 

                        service.Create(followup);

                    }

                    catch (Exception ex)

                    {

                        throw new InvalidPluginExecutionException(ex.Message);

                    }

                }

            }

        }

    }


Step 2: Signing the assembly:

Before Registering for the assembly, we need to sign in.

  • Right-click on the project, choose Properties.
  • Choose the Signing option.
  • Select the Sign the assembly box.
  • In the Choose a strong name key file box, choose Browse/new, and then navigate to the key file.
  • You may uncheck the Key to avoid password Authentication.




Signing an assembly ensures that the consumer knows its origin and uniquely identifies the component. It makes the physical DLL file tamper-proof.

A very important reason to sign an assembly is so you can be sure it is your assembly.

If we put the private key, others cannot sign an assembly with that same key.

Signing your dll makes the most sense when you verify those signatures before loading them. This ensures the integrity of all dll at runtime. It is a recommended security practice to sign all binaries that you ship and validate their signatures at runtime.

If we do not sign in to the assembly, we will get the below error:



Right Click on the Solution and build the Solution.

Step 3: Register the Plugin. Go to the Plugin registration tool.

Click on Create connection and then check the Display list of available Organizations. Click on login.


It will now retrieve the Organization you have logged in to. Enter the Organization credentials.


Click on Register >Register New Assembly.



Select the DLL file from the folder and add the register.


Load the assembly and now, click on Register and then Select Register new Step.


Since we are creating a follow-up task on the creation of lead, hence we will select the following:  

Message: Create

Primary Entity: Lead

Event Pipeline: Post Operation

Execution Mode: Synchronous.


Click on Register new Step.

Now, check the operation from Dynamics CRM. A follow-up task should be created on the creation of a lead record.




Synchronous and Asynchronous:

 

Synchronous plugins are triggered straight away.  So, if your plugin is triggered on the Create message, it will run directly either on post-operation or pre-operation. The CRM form will wait until the Synchronous plugin has finished processing before the form reloads. Can run on both post-operation and pre-operation. This will run only for 2 minutes and blocks users until completed.

 

Asynchronous plugins will be triggered sometime later when the CRM service has enough resources. We cannot assume when this will be triggered.  Async plugins do not slow the form reloading because it doesn’t have to wait. This will run only for 2 minutes and does not block users from seeing the operation result. Modifications happen after operations, so an update call is required.


Event Pipeline in Plugin:

When we run our Plugin, it is executed based on the Even pipeline :

 

·       Pre-Validation:- Security checks being performed to verify the calling or logged-on user has the correct permissions to perform the intended operation.

The Stage Value is 10.

For Example – In the “delete” plugin. If you need any information about the child records, the deleted plugin must be pre-validation.

·       Pre-Operation:- Execute before the main system operation. Plug-ins registered in this stage are executed within the database transaction.

The Stage Value is 20.

For Create message, this operation does not allow you access to the GUID generated after the creation of the record.

 

·       Core Operation:- The main operation of the system, such as create, update, delete, and so on. No custom plug-ins can be registered at this stage.

The Stage Value is 30.

 

·       Post-Operation:- Plug-ins that are to execute after the main operation. Plug-ins registered in this stage are executed within the database transaction.

The Stage Value is 40. 

 

Run in User’s Context: 

As we are creating a follow-up task on the creation of the account entity, we need to select the Run in User’s Context as a Calling user.

Suppose we select a user who does not have the privilege to create an activity task, then the plugin will not run-on execution.

Now, if we check the System, Jobs. You will see the plugin failed to execute.




Here are some other links for Troubleshooting and learning:

·       Plugin in Dynamic 365 CRM

·       Connect to Dynamic 365 CRM from Console App using Azure Authentication

·       Could not load file or assembly 'System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies

·       Unable to Login to Dynamics CRMOrganizationWebProxyClient is null

·       Assembly 'Microsoft.Crm.Sdk.Proxy' with identity 'Microsoft.Crm.Sdk.Proxy, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' uses 'Microsoft.Xrm.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' which has a higher version than referenced assembly 'Microsoft.Xrm.Sdk' with identity 'Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

·       Could not load file or assembly 'Microsoft.Xrm.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.

·       Could not load file or assembly 'Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies