Archive

Posts Tagged ‘Plugins’

[Step by Step] Dataverse | Plugins | Using Dependent Assemblies

In this article, I am going to highlight the limitations of conventional plug-in development and how the Dependent Assemblies feature addresses those limitations.

Limitations of the conventional plugins:

As we know that the plugins can be registered only as an individual .Net assembly, we can’t include another assembly or a resource file within a plug-in.

  • For example, you may want to use Newtonsoft.Json.dll or another assembly. You may want to access a list of localized strings which is not possible using native plugin development.

Workaround to support multiple assemblies:

ILMerge
  • One way to include another assembly is to combine it into one using ILMerge.
  • While ILMerge worked for many, it was never supported by Dataverse and it didn’t always work.
  • ILMerge is no longer being maintained.
Shared Projects
  • Other approach is by using Shared Projects.
  • In Shared Projects, the unit of reuse is the source code, and the shared code is incorporated into each assembly that references the shared project.

Both ‘ILMerge’ and ‘Shared Project’ options are workarounds and not recommended. Lets see how ‘Dependent Assemblies’ addresses these gaps.

Dependent Assemblies:

  • With dependent assemblies, rather than register an individual .NET assembly, you will upload a NuGet Package that contains your plug-in assembly and any dependent assemblies.
  • Unlike ILMerge, we can also include other file resources, such as JSON files containing localized strings. This NuGet package file is stored in a new table called “PluginPackage”.

If things are unclear at this point, dont worry, I will explain step by step with 2 scenarios. But before that, lets get the prerequisites ready.

Prerequisites:

  • Visual studio 2019 or later.
  • Download latest Plugin registration tool.
  • Download and Install Power Platform CLI
    • Don’t worry if you are not familiar with Power Platform CLI. We will not use complex commands.
    • We will only use one simple command to create Plugin project template.
  • Install NuGet Package Explorer
    • This is optional but a useful tool.
  • A blank solution in your Dataverse environment.

Once you got the prerequisites, lets gets started by creating plug-in assembly project.

Create a Plug-in project:

We will create plug-in project using Power Platform CLI command. As mentioned earlier, we only use CLI to create plug-in project. Steps as follows.

  • Create a new folder and open the ‘Command Prompt’.
  • Execute “pac plugin init” command.
  • “pac plugin init” command creates a .NET Framework Class library project which looks as below.
  • Open the project using Visual Studio and build. A new NuGet package gets generated for the project.

Now that we have project created, lets proceed with our first scenario.

Scenario 1 : Using ‘Newtonsoft.Json.dll’ in Plug-in project

Lets see how easily ‘Newtonsoft.Json.dll’ can be used in our plug-in project. The scenario I am using is on pre create off Account, I am setting ‘Name’ field by parsing json string.

  • Open the plug-in project created in previous step.
  • Rename the ‘Plugin1.cs’ file to ‘PreCreateAcount.cs’.
  • Install the ‘Newtonsoft.json’ package using Nuget Package Manager.
  • Add the following code snippet which uses JsonConvert.DeserializeObject method of NewtonSoft to “PreCreateAcount.cs” file
  • Build the project.
  • Note: With ‘Dependent Assemblies’ we dont need to sign the assemblies. Signing is optional. However ‘pac plugin init‘ command signs the assembly by default. So, go to project properties and uncheck the ‘Sign the assembly’.

View your NuGet package
  • Once you build the project, as an optional step, you can NuGet Package Explorer to examine the NuGet package.
  • Little bit of Dependent Assembly back ground logic , if you are interested.
    • When you upload your NuGet package, any assemblies that contain plugin classes will be registered in PluginAssembly table and associated with the PluginPackage.
    • At runtime, Dataverse copies the contents of the NuGet package from the PluginPackage row and extracts it to the sandbox runtime.
    • This way, any dependent assemblies needed for the plug-in are available.
Deploying the nuget package:
  • Build the project and open the plug-in registration tool.
  • Use ‘Register New Package’ and map the .nupkg file which will be available under your plug-in project bin\debug folder.
  • Select the Dataverse solution which we created as part of prerequisites. You can also use any existing solution.
  • Click on ‘Import’.
  • As a next step, register a new step on Pre Account Create, like how we used to create in regular plugin registration.
  • Post step registration, your Package should look similar as below.

Test the plugin:

As we developed and registered the plug-in package, its time to test.

  • Open a new Account from and provide some name.
  • Up on save, ‘Name’ should get replaced with ‘Rajeev Pentyala’ which is what we developed in our plug-in.

Scenario 2 : Using ‘Newtonsoft.Json.dll’ in another C# project

In scenario 1, we have seen how to use ‘Newtonsoft.Json.dll’ in the same plug-in assembly project. In scenario 2, lets see how to use another project.

  • Add a new ‘Class Library’ project. I named project as ‘Helper’.
  • Install the ‘Newtonsoft.json’ package using Nuget Package Manager.
  • Rename the ‘Class1.cs’ to ‘AccountHelper.cs’
  • Add following code snippet.
  • In the plug-in assembly project, add ‘Helper’ project as a project reference.
  • In the ‘PreCreateAcount.cs’ plugin class, call the AccountHelper.GetName()
  • Build the solution.

Update the nuget package:

As we changed the logic to fetch ‘Name’ from ‘Account Helper’ and built the solution. We should go and update the Plugin package.

  • To update the Plugin Package, in the ‘Plugin Registration Tool’, go to View ->Display by Package.
  • Select the latest .nupkg file and update.
  • Note : We have to go to View ->Display by Package to delete the package.
  • Test by creating a new Account record.

Limitations:

  • A plugin package is limited to 16 MB in size or 50 assemblies.
  • Workflow extensions, also known as workflow assemblies, workflow activities or custom workflow activities are not supported.
  • On-premises environments are not supported.

Hope you got some idea about ‘Dependency Assemblies’. Happy learning 🙂

Associate/Disassociate plugin messages in CRM

April 17, 2013 13 comments

In CRM, the Associate or Disassociate event happens

  • If you have a N:N relationship between two entities and when you try to associate or disassociate records either from Associated view or Sub grid.

Entity Associate View

Entity Associate View

In Plugins, the Associate & Disassociate messages behave little different than other messages.

  • When you register a plugin on Associate message, you have to leave “Primary and Secondary” entities as ‘none’.

Associate Plugin Step

Associate Plugin Step

  • Since we don’t provide entity names, the registered Plug-in step triggers on all “Associate” operations, so we have to check few conditions to let the “Association” trigger happen only between intended entities.

You can use the below code template for Associate or Disassociate plugins

            EntityReference targetEntity = null;

            string relationshipName = string.Empty;

            EntityReferenceCollection relatedEntities = null;

            EntityReference relatedEntity = null;

            if (context.MessageName == “Associate”) {

                // Get the “Relationship” Key from context

                if (context.InputParameters.Contains(“Relationship”)) {

                    relationshipName = context.InputParameters[“Relationship”].ToString();

                }                                   

                // Check the “Relationship Name” with your intended one

                if (relationshipName != “{YOUR RELATION NAME}”) {

                    return;

                } 

                // Get Entity 1 reference from “Target” Key from context

                if (context.InputParameters.Contains(“Target”) && context.InputParameters[“Target”] is EntityReference)  {

                    targetEntity = (EntityReference)context.InputParameters[“Target”];

                }                      

                // Get Entity 2 reference from ” RelatedEntities” Key from context

                if (context.InputParameters.Contains(“RelatedEntities”) && context.InputParameters[“RelatedEntities”] is EntityReferenceCollection) {

                    relatedEntities = context.InputParameters[“RelatedEntities”] as EntityReferenceCollection;

                    relatedEntity = relatedEntities[0];

                }

            }

🙂

“Query execution time exceeded the threshold” error in Plugins

Hi,

In one of my requirement I was accessing SSRS service API from my plugin to render and read the report

When the plugin execute the code, I was neither getting the expected result nor any error.

To troubleshoot the problem I open the event viewer and I got a warning stating below

Query execution time of 30.1 seconds exceeded the threshold of 10 seconds. Thread: 30; Database: orgname_MSCRM

Reason :- 

  • My plugin registered on Post Update of Account
  • In my plugin, I was rendering and reading a report which has dataset with “Select * From Account”
  • So the problem is with DB lock
    • On update of ‘Account’, a lock establish
    • In the Plugin code, when I try to render report it tries to execute “Select” statement on “Account” we get the above error

Fix :-

  • I modified my Select statement in report dataset with “No Lock” statement

             i.e., Select * From Account (nolock)

🙂

“The context is not currently tracking the entity” exception in CRM 2011

January 3, 2012 1 comment

Hi,

You may come across below exception when you are trying to Create/Update child record in the Parent record context of Plug-in using XRM Linq

Context is not currently tracking entity

Context is not currently tracking entity

Scenario :-

  • Imagine you have registered a “Post Update” Plug-in on ‘Account’ entity which Updates an associated ‘Contact’ entity
  • Here the Plug-in runs under Parent Entity Context (i.e., Account)
  • When you try to update child record (i.e.,Contact) it throws out exception, since the context knows nothing about ‘Contact’

Fix :-

  • The solution is call the context.Attach() method; Call this method before calling the Update method (Refer below code)

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

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

var ServiceContext= new XrmServiceContext(service);

Guid contactGUID= (from c in xrm.ContactSet where c.FullName == “Farest Chand” select c.Id).FirstOrDefault();

ServiceContext.Contact objContact= new ServiceContext.Contact {  Id = contactGUID,  FullName= ‘Rajeev’};

ServiceContext.ClearChanges();

ServiceContext.Attach(objContact);

ServiceContext.UpdateObject(objContact);

ServiceContext.SaveChanges();

Hope it Helps 🙂

Missing prvReadAsyncOperation privilege exception

September 21, 2011 3 comments

Hi,

Today my plug-in has thrown “Missing prvReadAsyncOperation privilege ” exception for user with one of the security role.

Fix:-

  • We need to grant Read Priveliege of System Job for the security role
  • Open the Security Role and go to Customization tab
  • Refer below screen

prvreadasync-privilage

prvreadasync-privilage

 

Hope it helps 🙂

Read Optionset value in Plugin CRM 2011

September 14, 2011 7 comments

Hi,

  Below is the sample code to read Picklist value (i.e., OptionSet Value) in CRM 2011

if (context.InputParameters.Contains(“Target”) && context.InputParameters[“Target”] isEntity)

{

currEntity = (Entity)context.InputParameters[“Target”];

}

int statusValue = -1;

string statusText=string.empty;

if (currEntity .Attributes.Contains(“statecode”))

{

OptionSetValue optionState = currEntity .Attributes[“statecode”] as OptionSetValue;

statusValue = optionTimesheetState.Value;

statusText = optionTimesheetState.Text;

}

Hope it helps 🙂