Monday, December 10, 2018

Append search column(s) in Quick Find View - Microsoft Dynamics 365

In Microsoft Dynamics 365, Quick find allows you to search record(s) on an entity. You can configure view and find columns in quick find view. You can add columns from the entity on which the the quick view is created.You can not add search columns of other related entities. If the requirement is to show matching contacts based on related entity search, then OOTB view customization will not allow you to do this.

In given ER diagram "Contact"and "Subscription" have N:N relationship through an intersection entity "ContactSubscription".



Records in Contact, Subscription and ContactSubscription entity

Contact Entity
Record1Record2
FirstNameAbhishekAlex
LastNameKumarGoldwin
Mobile9922032322
Emailab@d.comal@d.com
Subscription Entity
Record1Record2Record3Record4
SubscriptionTypePaidPaidPaidFree
NameNetFlixHBO GOPrimeHotStar
ContactSubscription Entity
Record1Record2Record3Record4
ContactAbhishek KumarAbhishek KumarAbhishek KumarAlex Goldwin
SubscriptionNetFlixHBO GOPrimeNetFlix
StartDate1-Jan-181-Jan-181-Jan-181-Jan-18
EndDate31-Dec-1931-Dec-1931-Dec-1931-Dec-19

In above table structure "Abhishek" have three subscriptions "NetFlix", "HBO GO" and "Prime" and "Alex" has one subscription "NetFlix".

In quick view we would not include subscription on contact grid search. If we do a search on keyword "NetFlix". We would not get any record.



The requirement is to search/show all the contacts based on there active subscriptions. E.g. for "NetFlix" it should show two records "Abhishek" and "Alex", for "HBO GO" and "Prime" it should show one contact "Abhishek".

Before we go on implementation its better to know that how CRM executes the Quickfind view? Internally CRM creates a query expression contains view and search columns with isquickfindfields property set true in filter condition. If you convert Queryexpression to FetchExpression the XML would look like as given below. You can extract Queryexpression by profiling Plugin on ReteriveMultiple step.


If we add conditions by manipulating the request in RetrieveMultiple Plugin, that would accomplish the requirement. Given below the code snippet.



In above code we have first extracted the contacts that have subscription provided in search string.
FetchExpression fexp = new FetchExpression("FetchXML query to get contact(s) on subscription(s)");
EntityCollection ecollection = service.RetrieveMultiple(fexp);

The resultant is then added to the search condition isquickfindfields criteria, which will return contacts matched with provided contactid.

foreach (Entity ent in ecollection.Entities)
{
  ConditionExpression cexpression = new ConditionExpression();
  cexpression.AttributeName = "contactid";
  cexpression.Operator = ConditionOperator.Equal;
  cexpression.Values.Add(ent.Id);
  filterexpression.AddCondition(cexpression);
}

Plugin Registration


Quick find Search for "NetFlix" subscription.


Quick find Search for "Prime" subscription.



Thursday, September 14, 2017

Solution Packager Tool - XrmToolKit

I have built a tool that provides an user interface and would help developers in setting up the arguments for Solution Packager. All you need to specify desired parameters for respective Pack or Extract Operation. This utility also has an interactive command window dedicated to Solution Packager.



This tool works with native Solution Packager executable provided by Microsoft Corporation, and needs to be specified in this tool. 

You are most welcomed to write your feedback and issues on this post or you can email me on abhishek_255@hotmail.

Monday, December 12, 2016

Tricky lost focus event call in supported way dynamics crm

I had an issue where I need to access CRM text field value on command click. Everything works perfectly well if user clicks on the form after text input (on change event is being called in this case). However things does not work when user hit the command button directly.

I found a solution that perfectly works well in my case. I have done three things

A. I have created a global variable in javascript to hold the state of object when the command button gets clicked.

B. On click of command button I have updated state in global variable and call Xrm.Page.data.save() method.

C. Create a javascript function and call it on form's save event. On save check who has initated the save click i.e. command button or by some other source.


Complete Code- 

var IsCommandClicked= false;

function onSave(context) {
    if (IsCommandClicked== true) {
        IsCommandClicked= false;
        var saveEvent = context.getEventArgs();
        saveEvent.preventDefault();
    }
}

function Command  Click() {
    IsCommandClicked= true;
    Xrm.Page.data.save();
}

Saturday, June 4, 2016

Clone a Solution - Microsoft Dynamics CRM 2016

Microsoft Dynamics CRM 2016 introduces a new feature Solution Cloning "Clone a Solution" - It creates a copy of solution with new version in which all patches released from base solution are merged.

You can only clone an unmanaged solution. If you clone an unmanaged base solution, it will create a new solution with higher version(Major & Minor) than base solution. And all the patches released from base solution will be merged into the cloned solution.

A cloned solution can be exported both Managed and Unmanaged

Import cloned solution in target system:

Import feature of clone solution is a bit different from normal solution, when you import a clone solution you will see a message - "This solution package contains an update for a solution that is already installed"

Current Version: 1.0.0.0
Version contained in the update: 1.1.0.0



Click on Next




Here you get option "Stage for Upgrade". If you select this option a holding solution will be created. It means you will see both base solution and upgraded solution. But the upgrade will not take place, to apply upgrade you need to click on "Apply Solution Upgrade" on Solution explorer form.

Maintain Customizations: Selecting this option will maintain any unmanaged customizations performed on components but also implies that some of the updates included in this solution will not take effect. 

Example: Suppose you have customized a field in default system solution and change its length from 50 to 100. If in case the cloned solution contains the same field with length 150. In this case maintain customization will retain the unmanaged customization i.e. field length will remain 100.

Overwrite Customizations: Selecting this option will overwrite any unmanaged customizations previously performed on components included in this solution. All updates included in this solution will take effect. From above example- In this case the field length will be updated to 150.

Clone a Patch: Refer Post

Thursday, June 2, 2016

Solution - Clone a Patch in Microsoft Dynamics CRM 2016

To perform and release customization in CRM from one system to another, usually we create "Solution", once done with customization(s) we export it either managed or unmanaged and deploy it to production.

Suppose a scenario where we have created a Solution (Solution-A), in that we have done some changes [added a new field say "new_field" length 50 for a entity] and deployed it to production.

Due to some reason now the requirement is to change the field length from 50 to 100. In earlier version to achieve it, either we directly update the field length in production or create a new solution (Solution-B) with all the changes and deploy it on production. 

To overcome this situation Microsoft Dynamics CRM 2016 introduces new feature "Clone a Patch". In which you can release fixes for the solution(s). In this scenario we can create Patch "Clone Patch" for Solution-A.

Benefits:
A. You can only create a patch Solution from a base Solution.
B. Patch solution can not be further patched.
C. There could be N no of patches from base Solution.
D. You can not install a patch if base solution is not available.
E. Patch solution version must have higher build and revision numbers and same major and minor version than base solution version.
F. Patches are only supported in CRM organizations of version 8.0 or later.
G. You can not update base solution, if it is patched.

Delete a Patch or Base Solution:

In the above example we have created two solutions (Solution-A and Solution-B). B is the patch for A and higher in version. To delete a base solution (Solution-A) 

Unmanaged : Then Solution-B must be deleted first then Solution-A

Managed: Solution-A can be deleted directly, Microsoft dynamics will remove all the patches in order from higher to lower version.

Thursday, April 21, 2016

Impersonate or Assign user in Microsoft Dynamics CRM


Impersonation is someone else working on your behalf to accomplish your task. In most integration scenarios with external applications non-interactive user account is used to impersonate an interactive user. 

Non-interactive account only works when "Act on behalf" privilege is assigned. Also it will execute within the security role boundary of Interactive user. So an interactive user have access to case entity create - user or team level and on other hand non-interactive have access  at Organization level. Then only user and team level access will be granted to non-interactive. Impersonation is best where an operation shall execute in the interactive user security role context.

The above approach does not guarantee that an operation will always get complete, suppose a scenario where case-create role revoked from the interactive user, then non-interactive user acting on behalf of interactive user will not be able to perform create operation.

If the requirement is that always a case get created in dynamics CRM, then we can configure non-interactive user account and grant organization level access to create a case and assign etc, once case get created  it can be assigned to any interactive user. The difference you see here is created by user will non-interactive & owner will be interactive when you assign. On the other hand if you impersonate then created by and owner both will be interactive.



Sunday, April 17, 2016

Plugin Error to Entity Microsoft Dynamics CRM

Plugin(s) are used to apply custom business logic within organization service's event execution pipeline. In event of any exception the execution of plugin code terminates along with core operation. If you have enabled the exception logging of plugin exception (Settings>>Administration>>System Setting>>Customization>>Enable logging to Plugin Trace log >> Exception), plugin exception will be logged in Plugin Trace log.


Plugin Trace Log is a centralized view for all the plugin exceptions. Tracing of plugin exception to custom entity is not possible without customization and configuration. In this post we will see an approach to log plugin exception(s) to custom entity.



Requirement is to write a plugin on contact create, that plugin will validate "First Name", if first name is left blank then contact should not get created and plugin will throw error and terminates the core operation. And this specific plugin error needs to logged into "ContactPluginError" entity.




In above process flow chat, a recursive workflow will be running in background that will be triggered in every X minutes, it will create a custom entity record recursively, on that custom entity there will be a post operation registered plugin which will read & delete error detail from Plug-in trace log and move it to custom entity.

A. Enable Plug-in exception tracing

Plugin errors will be logged to Plug-in trace log when enabled from system settings. 



B. Custom Entity "ContactPluginError"

Create custom entity to log plug-in error. This entity will appear in Setting area.



Add fields to store exception details.




Customize "ContactPluginError" form to display error details.


Save and Publish customizations.


C. Custom Entity "RecursiveMovePluginError"

RecursiveMovePluginError entity will be created by workflow, this entity will have a plugin registered on create which will read data from plugin trace log entity and move it to custom entity. 


Add a field to store the type (plugin name) whose error log needs to moved from plugin trace log to ContactPluginError entity.



Customize RecursiveMovePluginError form and add field type.



Save and Publish Customization.

D. Create Workflow

Create background on demand workflow, that needs to be first triggered manually, once triggered it will automatically executes every 2 minutes and create RecursiveMovePluginError entity record.



Set below properties on Create step of RecursiveMovePluginError record.


Save and activate the workflow.

D. Plugin

Create and register "TracePlugin" plugin that will be move exception from Plugin trace log to custom entity.





Register plugin Post operation - Async



E. Execute and Trigger Process

Create Contact record without first name, an exception will the thrown by plugin

System plug-in trace log will be having an entry for this plugin error.



Configure and Trigger workflow job to move errors to ContactPluginError entity. Create a record for RecursiveMovePluginError and specify plugin type that needs to be monitored and moved.


Trigger workflow





Now all the plugin error thrown by plugin type "ContactDataValidation.FirstNamePlugin" will be moved from plugin trace log to custom entity "ContactPluginError".





Summary:

"Plugintracelog" entity does not expose "Create" message to register any plugin. Therefore when any record is created in "Plugintracelog"  entity there is no way to directly fire any plugin and perform any action on that.

Recursive workflows are auto triggered, so whenever a new record "RecursiveMovePluginError " is created, registered plugin "TracePlugin"  on "RecursiveMovePluginError" entity create message will also execute, its task is to read all the matched types "ContactDataValidation" plugin logs and move it to custom entity "ContactPluginError". Since I have configured workflow with a timeout condition of 2 minutes, so 2 minutes delay is expected in move operation from "PluginTracelog" entity to  "ContactPluginError" entity.


For Reference:

Solution File:




Plugin Code: