Wednesday, February 5, 2014

Error: Unable to load plug-in Assembly in offline mode for Dynamics CRM 2011 / CRM 2013

Hi Guys,

If you are working on Dynamics CRM 2011 or 2013, and you need to work with offline mode of CRM Outlook Client. And when you do something that need a custom plugin execution. You may come face-to-face with this kind of probleme :

Error Message : Unable to load plug-in Assembly


 And when you download the log file you will see something like this :

Public key token 0868a8a927707e20 is not found in allow list.


The reason for this error is that when you install the CRM Outlook offline client, this one adds in your system registry a new entry called Allow List that contains all public token keys of the allowed plugins. But, this Allow List don't contain the public token key of your plugin. You need to add all public token keys of the offline plugins in this Allow List.

To do it you need to :

  • Open your PRT (Plugin Registration Tool).
  • Select, one by one, all plugins that contain offline mode. Properties window will contains all details about your plugin
  • Copy the public key token like this.


  • You need to open your system registry
  • Navigate to this location : HKEY_CURRENT_USER\Software\Microsoft\MSCRMClient\AllowList

  • Click on AllowList and create a new key:

  • Paste the public token key in the name of the new key.
  • Repeat this operation for all offline plugins

Have a nice day,

N.JL

Tuesday, February 4, 2014

How to programmatically initilize mapped attributes when you create a new record

Hi Guys,

When you have a 1:N relationship in Dynamics CRM 2011/2013 between two entities such as Account and Contact, this relationship can be respresented by a subgrid of contacts on the account form.

If this relationship contains some mapping attributes, and you want to create a contact from this subgrid, the new contact record will contains all mapped attributes with data from the parent account record. but when you want to create this record programmatically using a plugin, this mapping will dont work.

To force this mapping using the code, you need to use InitializeFromRequest - InitializeFromResponse.

The InitializeFromRequest - InitializeFromResponse message allow CRM to initialize all mapping attribute between source and target entities.

the InitializeFromResponse object contain a member called Entity that contains a memory image of the target entity record with all mapped attributes. So you need to get this Entity object and call service.create().

There is an example that illustrate this case :

  // Allow CRM to initialize all mapping attributes between account and contact entities.
  InitializeFromRequest initializeFromRequest = new InitializeFromRequest();
  initializeFromRequest.EntityMoniker = new EntityReference("account", accountRecord.Id);
  initializeFromRequest.TargetEntityName = "contact";
  initializeFromRequest.TargetFieldType = TargetFieldType.All;

  InitializeFromResponse initializeFromResponse = (InitializeFromResponse)service.Execute(initializeFromRequest);


  // Create a new contact record with all initialized mapped attributes
  Entity contact = initializeFromResponse.Entity;
  service.Create(contact);



have a nice day.

N.JL

Monday, July 8, 2013

How to resolve this problem SecLib::AccessCheckEx failed.

Hi Guys,

If someone had an error like this one while testing a scenario on his  CRM 2011 organization:

Unhandled Exception: System.ServiceModel.FaultException
PluginName : SecLib::AccessCheckEx failed. 
Returned hr = -2147187962, 
ObjectID: 8f3a3333-09e3-e211-b4c7-0050568c06b4, 
OwnerId: a9acc15c-95d2-e211-b3ed-0050568c06b4,  
OwnerIdType: 8 
and CallingUser: 576bd94b-27e3-e211-9980-0050568c06b4. 

ObjectTypeCode: 10008, 
objectBusinessUnitId: 6fad00e6-71d2-e211-b3ed-0050568c06b4, AccessRights: WriteAccess 


Don't worry, it's a right problem. But to resolve it, you need to have a database access to the CRM Sql Server.

You need to verify these points :

- If you don't know who is the CallingUser with the id : 576bd94b-27e3-e211-9980-0050568c06b4 you need to make a search on SystemUser table.

USE [ORGANIZATION_MSCRM]
GO

SELECT * FROM SystemUserBase WHERE SystemUserId = '56C9CC2B-E2C4-4012-B946-34024CBBA15A'

- After that, you need to enumerate the user's roles.
- Then, You need to detect the entity that generate the problem. To do this, you need to use the Object Type Code information : ObjectTypeCode: 10008


USE [ORGANIZATION_MSCRM]
GO

SELECT * fROM EntityView WHERE ObjectTypeCode = 10008

Execute this query to get entity name,

- Finnally, use this information : AccessRights: WriteAccess to verify in all user's roles if this entity had write privilege

You will find that any role has this privilege on this entity.

So, add this privilege to the role that you want and retry your scenario. You will see that it works.

have a nice day.

N.JL



Thursday, June 27, 2013

How to use Fiddler to debug CRM 2011 Javascript and HTML Webresources


Hi Guys,

In order to properly develop JavaScript and/or Html webresources, a CRM 2011 developer needs to make many publications on CRM development server, sometimes, with many errors. And when a team works on the same server, especially on the same entity, that can make the work troublesome and make any back slowly during these publications.

Using Fiddler 2 locally as an auto-responder is the solution.  


As a web debugging proxy, Fiddler will intercept any session (web call) outgoing form your local machine. And it can redirect some session to call instead of letting it out to web server. This is the role of the Auto-Responder.



And now, follow these steps:


  1. Launch Fiddler 2
  2. Make a Filter to show only sessions going to CRM Server like this:

  3. After this operation, select all session in the “Web Sessions” list and remove theme.

  4. Open IE and go to “ Inernet Option”, and delete “Temporary Internet Files and Website Files” like this :


  5. Back to Fiddler and click to Autoresponder tab.
  6. Ckeck this two options

  7. In Web Sessions List, Select Session line corresponding to your javascript/Html webresource that you want to work on then, drag and drop it in " If URI Matchs..." list.


  8. That add a line in this list. This line starts With the keyword : "EXACT". The same line is added in the first combbox of the "Rule Editor", and a in the second combobox this string "*200-SESSION_211" is added.


  9. You need to replace EXACT keyword by REGEX keyword In the first combobox, then replace the entire URL string up before the name of the WebResources by "*/" and finally you need to add ".*" in the end of string like this : 
  10. EXACT:http://ServerName/OrgName/WebResources/new__common.utilities.js
    become
    REGEX:.*/new_common.utilities.js.*



  11. After that, in the second combobox, put the local file path of your webresource like this:




  12. Finally click to Save.
Repeat this operation for all your webresources that you want to work on. and not forget to empty Temporary IE Files everytime you want to put a new webresource.

Have a nice Day.

I hope that this post helps you.

N.JL

Monday, December 31, 2012

Useful Javascript functions for CRM 2011

Hello everybody,

When we want to manipulate some objects in a Dynamics CRM 2011 entity form interactively, the first think that we think, is to use Javascript methods.

So, we start by searching some methods to manipulate an attribute, a navigation item ... And we waste many time to search on the internet if there is a method to do that thing or not ...

It is for this reason that I have gathered all the methods that I thought they may help the Dynamics CRM 2011 Developer in a one Javascript Library that I called FormHelper.

You can download this Library right here.

There is the list of Javascript Functions :

Usefull Information
  • GetServerUrl()
  • GetOrganisationName()
  • GetEntityId()
  • GetEntityName()
  • GetCurrentUserId()
  • GetCurrentUserRoles()
  • GetEntityOwnerId()
  • GetEntityState()
Managing Attributes
  • GetAttributeValue(attributeName)
  • SetAttributeValue(attributeName, attributeValue)
  • GetAttributeLabel(attributeName)
  • SetAttributeLabel(attributeName, label)
  • GetAttributeVisibility(attributeName)
  • SetAttributeVisibility(attributeName, visible)
  • GetAttributeRequirementLevel(attributeName)
  • SetAttributeRequirementLevel(attributeName, requirementLevel)
  • GetAttributeState(attributeName)
  • SetAttributeState(attributeName, disabled)
  • SetFocusOnAttribute(attributeName)
Managing Tabs, Sections & Nav Items
  • GetTabLabel(tabId)
  • SetTabLabel(tabId, newLabel)
  • GetTabDisplayState(tabId)
  • SetTabDisplayState(tabId, newTabState)
  • ManageTabVisibility(tabId, visible)
  • GetSectionLabel(tabId, sectionId)
  • SetSectionLabel(tabId, sectionId, newLabel)
  • ManageSectionVisibility(tabId, sectionId, visible)
  • GetNavItemLabel(navItemId)
  • SetNavItemLabel(navItemId, newLabel)
  • ManageNavItemVisibility(navItemId, visible)
Other Functions
  • IsIFrame(controlName)
  • IsSubgrid(controlName)
  • IsLookup(controlName)
  • IsOptionSet(attributeName)
  • GetIframeUrl(iframeId)
  • RefreshSubGrid(subgridId)
  • GetOptionSetText(attributeName)
  • SetLookupValue(attributeName, lookupId, lookupName, entityName)
  • ClearLookup(attributeName)
  • CallOnChangeEvent(attributeName)

I hope that this javascript functions can help you.

Have a nice day.
N.JL


Tuesday, May 15, 2012

Comment changer le contenu de la vue associée par défaut d'une entité

Bonjour,


Une des problématiques qui rencontrent un développeur CRM est la suivante :


Comment changer le contenu de la vue associée par défaut (Default Associated View) d'une entité


Au niveau du serveur CRM de mon client, j'ai plusieurs entités dont l'entité Compte et l'entité Devis. Chaque enregistrement compte pourra avoir 0 ou plusieurs enregistrements devis associés en différents statuts Brouillon, Actif, Conclu, Fermé...
Or, lors de l'ouverture du formulaire d'un enregistrement compte, si on clique au niveau du Navigation bar sur le bouton Devis on tombe toujours sur une subgrid qui affiche les devis en statut Brouillon. Alors que mon client veut que si on clique sur Devis on devrait trouver par défaut tous les devis pas que ceux dont le statut est Brouillon.







Pour le faire, il faut suivre les étapes suivantes :


étape 1 :


Pour réaliser cette tâche, Il y'a deux façon de le faire : 
- Soit de copier/coller et de faire tout en mode machine vite fait et basta.
- Soit de comprendre la solution derrière. 
Pour ceux qui optent pour la 1ère façon, qu'ils passent directement vers l'étape suivante.
Pour le reste, suivez moi.
Pour pouvoir afficher la Vue associée Devis, il suffit d'appuyer sur le bouton Devis, d'attendre à ce que le subgrid se recharge et voila, la liste des Devis en statut Brouillon est chargée. 
Maintenant, Il est obligatoire d'identifier certain objets au niveau du formulaire. Ces objets, je pense déjà que vous avez eu une idée, les voilà : 
  1. Le bouton Devis.
  2. Le conteneur dans le quel se charge le subgrid de vue associée.
  3. Le subgrid  
  4. Le  comboBox qui contient les stauts

pour les identifier. appuyer sur F12. Si rien ne se passe, c'est qu'il vous manque le Microsoft Dynamics CRM Developer Tool. Chercher le sur internet et installer le.


Sinon, c'est ce que vous aurez :




Appuyer, sur le bouton qui représente une flèche
En survolant chaque objet sur le formulaire, un contour bleu se dessine sur cet objet. Survoler le bouton Devis et cliquer dessus.
La fenêtre en bas à gauche va changer de contenu et va souligner en bleu le code HTML représentant le bouton Devis. Bouger la scrollbar jusqu'à un peu plus que le milieu. et là ça se trouve l'attribut id de l'objet.
Donc si on refait la même chose pour les 4 objets précédemment cités. On trouve ceci.
  1. id du bouton Devis. = navQuotes
  2. id de l'iFrame dans le quel se charge le subgrid de vue associée.  = areaQuotesFrame
  3. id du subgrid = AppGridFilterContainer
  4. id du  comboBox qui contient les stauts = crmGrid_quote_customer_accounts_statecode
Donc le process va être le suivant en cliquant sur le bouton navQuotes, on va attendre que le iFrame areaQuotesFrame se charge complètement, puis on va dire au comboBox crmGrid_quote_customer_accounts_statecode de changer de DefaultView et de rafraichir le subgrid AppGridFilterContainer.


Une autre question qui se pose est la suivante : 
Qu'est ce que je vais mettre au niveau dur valeur de Combobox ? 
La réponse est simple :
- Si j'ai envie d'afficher toutes les devis avec n'importe quel statut alors je mis comme valeur = "All" qui veut dire bien sur Tout.
- Sinon, si par exemple mon client change d'avis et qu'il veut afficher par exemple que les devis actifs, ou les devis conclus ... alors il faut tout simplement mettre la valeur correspondant à ce statut au niveau de l'attribut statuscode de l'entité devis (quote). 
c'est à dire:

Statut Valeur
Brouillon 1
Actif 2
Conclu 4
Fermé 6
Tout All


étape 2 :


Au niveau de la solution par défaut au niveau du serveur CRM, Sélectionner Ressources Web.
Appuyer sur Nouveau.




Renseigner les  champs Nom, Nom complet et Type comme dans l'image ci-dessus.
Puis, appuyer sur le bouton Éditeur de texte
Coller le script ci-après dans la fenêtre qui va s'ouvrir.


if (typeof (NJL) == "undefined")
{ NJL = { __namespace: true }; }
NJL.Account = {
 SetDefaultView: function(viewCombo, viewName, appGrid) {
  if (viewCombo.value != viewName) {
   viewCombo.value = viewName;
   appGrid.RefreshGridView();
  }
 },
 areaQuotesFrame_OnReadyStateChange: function() {
  if (this.readyState == "complete") {
   var frame = document.frames("areaQuotesFrame");
   var viewCombo = frame.document.getElementById("crmGrid_quote_customer_accounts_statecode");
   var appGrid = frame.document.getElementById("AppGridFilterContainer");

   if (viewCombo.readyState == "complete") {
    NJL.Account.SetDefaultView(viewCombo, "All", appGrid);
   }
   else {
    viewCombo.onreadystatechange = function() {
     if (this.readyState == "complete") {
      NJL.Account.SetDefaultView(this, "All", appGrid);
     }
    }
   }
  }
 },
 formOnLoad: function(){
  if (document.getElementById('navQuotes') != null) {
   document.getElementById('navQuotes').onclick = function() {
    loadArea('areaQuotes');
    document.frames('areaQuotesFrame').document.onreadystatechange = NJL.Account.areaQuotesFrame_OnReadyStateChange;
   }
  }
 }
}



Enregistrer la ressource web.

étape 3 :

Au niveau du  Formulaire Compte, Onglet Personnaliser, Appuyer sur Personnaliser l'entité.  
Puis au niveau des propriétés du Formulaire, Ajouter la ressource web, et au niveau de l'évenement OnLoad ajouter la fonction NJL.Account.formOnLoad.

étape 4 :


Publier et admirer le résultat.


N.JL

Wednesday, May 9, 2012

Comment gérer l'activation et/ou l'affichage d'un bouton sur le Ribbon CRM 2011 en fonction du rôle de sécurité

Bonjour,


En tant qu'expert technique Dynamics CRM, je tombe souvent sur cette problématique. Donc, j'ai décidé de publier ce post en se mettant dans un contexte réel. 


Objectif :

Mon client veut que toute personne ayant le rôle "Commercial TLV" ne doit pas pouvoir fermer une opportunité comme perdu. En d'autres terme, il doit pas avoir le droit de cliquer sur ce bouton au niveau de l'opportunité:


P.S : Avant de avoir recours à cette méthode, il faut s'assurer qu'il y'a que cette méthode pour y arriver. car pour certaines cas, par exemple, tel que fusionner des contacts. au lieu d'utiliser cette méthode pour cacher ce bouton : 


il suffit de sélectionner le rôle concerné, appuyer sur l'onglet "Gestion d'entreprise", de regarder au niveau des "Privilèges divers" et désactiver le privilège "Fusionner".


Comment Faire :



1ère étape : Enregistrer le script çi-après au niveau des ressources web de votre solution sous un nom que vous choisissez, par exemple : new_ManagingRole.js



 // Retourne True si l'utilisateur possède le rôle introduit en paramètre sinon il retourne False
function UserHasRole(roleName) {
 
    var serverUrl = Xrm.Page.context.getServerUrl();
    var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
    oDataEndpointUrl += "RoleSet?$top=1&$filter=Name eq '" + roleName + "'";
    var service = GetRequestObject();
    if (service != null) {
        service.open("GET", oDataEndpointUrl, false);
        service.setRequestHeader("X-Requested-Width", "XMLHttpRequest");
        service.setRequestHeader("Accept", "application/json, text/javascript, */*");
        service.send(null);
        var requestResults = eval('(' + service.responseText + ')').d;
        if (requestResults != null && requestResults.results.length == 1) {
            var role = requestResults.results[0]; 
            var id = role.RoleId;
            var currentUserRoles = Xrm.Page.context.getUserRoles();
            for (var i = 0; i < currentUserRoles.length; i++) {
                var userRole = currentUserRoles[i];
                if (GuidsAreEqual(userRole, id)) {
                    return true;
                }
            }
        }
    }
 
    return false;
}
 
// retourne l'objet XMLHttpRequest
function GetRequestObject() {
    if (window.XMLHttpRequest) {
        return new window.XMLHttpRequest;
    }
    else {
        try {
            return new ActiveXObject("MSXML2.XMLHTTP.3.0");
        }
        catch (ex) {
            return null;
        }
    }
}

// Compare 2 GUID values
function GuidsAreEqual(guid1, guid2) {
    var isEqual = false;
    if (guid1 == null || guid2 == null) {
        isEqual = false;
    }
    else {
        isEqual = guid1.replace(/[{}]/g, "").toLowerCase() == guid2.replace(/[{}]/g, "").toLowerCase();
    }
 
    return isEqual;
}

// la méthode d'entrée.
function callMain() {
 
if(UserHasRole("Commercial TLV"))
{
return false;
}
else 
{
return true;
}
 
}

2ième étape : Installer un outil de gestion de Ribbon tel que Ribbon Workbench .


3ième étape : Créer la nouvelle solution ManagingRoles, ajouter l'entité opportunité.



et il ne faut pas inclure les composants reliées à l'opportunité.





4ième étape : 
Ouvrir l'outil Ribbon Workbench (RW) à partir du ribbon de CRM sur le HomePage des Solutions. via le bouton Personnaliser.




Au niveau de l'écran de RW, sélectionner la solution ManagingRoles.






L'outil charge les Ribbons des entités de la solution sélectionnée.


Maintenant, selon notre choix, soit on veut que le bouton sera caché totalement, soit on veut juste le désactiver.


On dispose de ces deux type de règles :







  • Les Display Rules
  • Les Enable Rules
Supposant, qu'on veut juste le désactiver. Alors, il suffit d'ajouter une nouvelle règle en cliquant sur Enable Rules.



Renommer la règle comme suit : new.opportunity.CustomcheckRole

Appuyer sur Steps et choisir Custom Javascript Rule.


Puis au niveau du champ Library il faut choisir le la ressource web new_ManagingRole.js. Et au niveau du champ FunctionName, définir CallMainPuis appuyer sur OK


5ième étape : 

Un détail très important, en général, et comme pour ce cas là, le bouton "Fermer comme perdu" existe sur le HomePage et sur le Formulaire. Donc cette opération devrait être appliquée sur les deux modes HomePage et Form.




Pour ceci, il faut déja choisir l'un des deux mode. Pour le faire c'est facile. Au niveau du coin droit en haut de l'écran de RW sous le nom de la solution, il faut choisir l'un des deux. Par défaut c'est HomePage qui est choisi. En choisissant le mode, RW recharge instantanément les boutons de ce mode.


Je vais choisir le mode Form en premier.




Ensuite, il faut sélectionner le bouton en question. cliquer droit sur ce bouton via le souris, un menu contextuel apparaît. Il faut choisir le menuItem Customise Command.






La commande associée au bouton apparaît au niveau de la liste des commandes.






Sélectionner cette commande. Et au niveau de champ EnableRules






Ajouter la règle : new.opportunity.CustomcheckRole en tant que la première sur la liste.

Cette étape est à refaire pour le mode HomePage.


Dernière étape : Appuyer sur Publish Solution pour pouvoir publier toute ces modifications.



Bonne lecture.

N.JL

Friday, May 4, 2012

Ribbon Workbench l'outil de gestion de Ribbon par excellence sur CRM 2011 onPremise

Le Ribbon Workbench version beta est un outil de gestion de Ribbon sur CRM 2011.


Développé en Silverlight, il s'intègre en tant que ressource web lors de l'import de la solution managé RibbonWorkbench_1_0_0_259_managed.zip à partir de l'interface de gestion des solutions. 

















Il permet de faire ceci :


Les Controls Ribbon :

  • Ajouter un button standard
  • Add a ancre de menu (Flyout Anchor)
  • Ajouter un boutton de séparation (Split Button)
  • Ajouter un élément de menu. (Menu Item)
  • Renommer un control existant
  • Cacher un control existant
  • Bouger les controls en personnalisant les sections : tab / group / menu 




Les Commandes :

  • Modifier les commandes standards
  • Modifier les règles d'affichage (display rules)
  • Modifier les règles d'habilitation (enable rules)
  • Ajouter des nouvelles  commandes


Les Groupes :

  • Ajouter de nouveaux groupes dans un onglet existant ou dans un nouveau.
  • Bouger un groupe dans un onglet existant ou dans un nouveau
  • Changer la position des bouttons
  • Changer le modèle d'un onglet existant ou dans un nouveau (layout template)
  • Renommer un groupe existant


Les Menus :

  • Ajouter des sections du menu supplémentaires dans un menu existant
  • Ajouter de nouveaux éléments de menu (menu items)
  • Ré-organiser les éléments de menu et les sections


Les Onglets (Tab) :

  • Ajouter de nouveaux onglets
  • Personnaliser un onglet existant
  • Renommer un onglet existant
  • Changer le comportement d'échelle de l'onglet (the scaling behavior)


Les Types de Ribbons :


  • Entité & Application
  • Home Page
  • Sub Grid
  • Ribbon du formulaire
  • Onglet de Visualisations
  • Menu Jewel

Instructions d'installation :


  1. Télécharger la solution à partir de ce lien.
  2. Installer la dans votre organisation CRM 2011 via le boutton importer. 



Une fois installé, vous verrez le bouton 'Personnaliser' de Ribbon Workbench apparaitre dans le ruban du 'Home Page' lorsque vous sélectionner le lien "Solutions" ou le lien "Personnalisations".






Vous pouvez regarder ce tutorial simple qui montre comment installer et utiliser RW.



N.JL