Doing a migration of a CRM 4.0 system from one environment to another, I ran into this problem:
The target environment was a test environment and the owner of the environment assigned ‘only’ 2 GB of RAM.

CPU 100%
Immediately after I imported the organization using the Deployment Manager, the CrmAsyncService spiked the CPU and the memory load up to nearly 100% constantly…

Solution
Because we migrated from a machine that had enough RAM to a machine with 2GB (on a 64 bit machine…), the solution was to change the values of the fields ‘IntColumn’ in the Table: ‘DeploymentProperties’ of the ‘MSCRM_CONFIG’ database where the ColumName equals ‘AsyncInMemoryHigh’ and ‘AsyncInMemoryLow’.

crm_asyncsettings
Fig 1: DeploymentProperties table

The values that worked for us are:

ColumnName IntColumn
AsyncInMemoryHigh 50
AsyncInMemoryLow 20

These values are a lot higher in a default Crm implementation, something like 5000 and 2000, so the values I use here are only in case of very low memory.

After a restart of the CrmAsyncService (kill process and manually restart service, or wait for it to come up again), the problem was gone and Performance Monitor showed that the workflows (which caused the problem) where processed again.

What these settings do is they dictate the CrmAsyncService to take the amount specified in the AsyncItemsInMemoryHigh IntColumn of tasks to process in memory (and no more than is specified).
The service will process these tasks one at a time, untill it reaches the amount specified in the AsyncItemsInMemoryLow IntColumn, it than takes the amount of tasks in memory, that are specified in the AsyncItemsInMemoryHigh IntColumn again, until there are no more tasks to process.

Henry Cordes
My thoughts exactly…

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Using jQuery with MS CRM 4.0

Published 11/21/2008 by Henry in CRM | Javascript | jQuery

Doing a MS CRM 4.0 project, where the requirement is to create a toolbar button on a detailform.
This button needs to open a window (prefferably a modal window). In this window users can make some selections and when submitting, some processing will be done using these selections, this is not important for this post.

When thinking about this requirement, I really wanted to use something like the ASP.NET AJAX Control ToolKit's Modal Popup. Also I am really impressed by jQuery, a JavaScript library, that is an elegant and easy to use abstraction over JavaScript. It simplifies document traversing, event handling, animation and Ajax interactions. I knew about jqModal a jQuery plugin that simplifies display of dialogs and modal windows.

NOT FULLY SUPPORTED
If you are a developer
working with MS CRM, you know that it is higly customizable, but within it's own boundries. An important matter on this project particularly is that customizations need to be supported by Microsoft. What I am about to explain is NOT FULLY SUPPORTED, because I will use external.js files, using a link element to import it in the page. But I want to explain also, that it is possible to do this without using external files, you could paste the contents of the 'jquery-1.2.6.min.js' file into the onload function of the detailform's property window.

I wanted to give it a try, because, well just think about the possibilities for a while. If you can use jQuery in CRM development, a lot of possibilities open up.

FIRST STEPS
So the first thing to do is to put the 'jquery-1.2.6.min.js' file in a '_customscript' folder in the CRMWEB root folder. Next I need a way to reference the file, so it's contents can be called from the page. Like I already posted in my blogpost External js file and CRM, I like to do this using the Msxml2.XMLHTTP object. The function reads the contents of a file and imports all functions found into the current namespace, so they are accessible.

   1:  function load_script (url) 
   2:  { 
   3:      var x = new ActiveXObject("Msxml2.XMLHTTP"); 
   4:      x.open('GET', url, false); x.send(''); 
   5:      eval(x.responseText); 
   6:      var s = x.responseText.split(/\n/); 
   7:      var r = /^function\s*([a-z_]+)/i; 
   8:      for (var i = 0; i < s.length; i++) 
   9:      { 
  10:          var m = r.exec(s[i]); 
  11:          if (m != null) 
  12:              window[m[1]] = eval(m[1]); 
  13:      } 
  14:  } 
  15:   
  16:  load_script("/_customscript/jquery-1.2.6.min.js"); 
  17:  load_script("/_customscript/jqModal.js"); 
  18:  load_script("/_customscript/jqDnR.js"); 
  19:  load_script("/_customscript/customscript.js"); 

Listing 1

As you can read in listing 1, the 'jqModal.js' file is also referenced, this holds the jqModal library, I also load 'jqDnR.js' a jQuery library that supports dragging and resizing. I also load 'customscript.js', this is a custom javascript file that will hold the function that is called when the button on the details window is clicked.

CSS STYLESHEET
Because we do not want to mess with the stylesheets used by CRM we also need to add a stylesheet containig the modal window's styles to the filesystem. I made a css folder below the _customscript folder, the folder where I put the javascript libraries. You could add these styles through Dom manipulation in JavaScript also, to keep the customization supported by Microsoft!
I use the following code, you can do this in the OnLoad function of the details form, or in a separate function, that you call from the Onload function. I use the function that also checks if the reference exists already, but for simplicity put this in the On Load after listing 1.

   1:  var styleSheet = '/_customscript/css/modalWindow.css';
   2:  var head = document.getElementsByTagName("head")[0];
   3:  var linkElement = document.createElement('<link rel="stylesheet" type="text/css" href="'+ styleSheet +'" />');
   4:  head.appendChild(linkElement);

Listing 2

In listing 2 I create a link element with a reference to a style sheet and append this element to the head element of the html page (CRM's detail form).

Listing 3 will display the contents of the css style sheet:

   1:  .jqmWindow  
   2:  { 
   3:  	display: none; 
   4:  	position: fixed; 
   5:  	top: 17%; 
   6:  	left: 50%; 
   7:  	margin-left: -300px; 
   8:  	background-color: #E4EEF9; 
   9:  	border-width: 1px; 
  10:  	border-style: solid; 
  11:  	border-color: #0a6cce; 
  12:  	padding: 0px; 
  13:  	width: 374px; 
  12:  	height: 264px; 
  13:  } 
  14:  
  15:  .jqmOverlay { filter: alpha(opacity=70); opacity: 0.7; }
  16:  
  17:  .jqmTitle 
  18:  { 
  19:  	cursor: move; 
  20:  	background-color: #6793CC; 
  21:  	border: solid 1px #6793CC; 
  22:  	color: #FFFFFF; 
  23:  	font-weight: bold; 
  24:  	width: 100%; 
  25:  } 
  26:  
  27:  .jqmTitleText { float: left; position: relative; }
  28:  
  29:   /* Fixed posistioning emulation for IE6  
  30:      Star selector used to hide definition from browsers other than IE6  
  31:      For valid CSS, use a conditional include instead */  
  32:  * html .jqmWindow 
  33:  { 
  34:    position: absolute; 
  35:    top: expression((document.documentElement.scrollTop || document.body.scrollTop) + 
  36:         Math.round(17 * (document.documentElement.offsetHeight || document.body.clientHeight) / 100) + 'px'); 
  37:  } 
  38:  
  39:  .jqmIFrame { width: 100%; height: 100%; }
  40:  
  41:  .jqmClose 
  42:  {  
  43:    width: 20px; 
  44:  	font-weight: bold; 
  45:    float: right; 
  46:  	cursor: pointer; 
  47:    color: #FFFFFF; 
  48:  	background: #6793CC; 
  49:    border: 1px solid #6793CC; 
  50:  }  

Listing 3

CREATE DIV (MODAL WINDOW)
Next we need to add the div to CRM's details page. I wanted to this using the DOM, but for some reason it would not work. If anybody knows the reason why, please let me know!
Instead i used  the following approach, again: you can do this in the OnLoad function of the details form, or in a separate function, that you call from the Onload function.
In the real world project I use the function, but for simplicity in this example, I just put this in the On Load after listing 2.

   1:  // Not using dom to add new elements, because for some reason that does not work!
   2:  var body = document.getElementsByTagName("body")[0];
   3:  var modalDiv = document.createElement('<div id="dialog" class="jqmWindow" ></div>');
   4:  var titleDiv = document.createElement('<div id="jqmTitle" class="jqmTitle"></div>');
   5:  var modalTitle = document.createElement('<span id="jqmTitleText" class="jqmTitleText"></span>');
   6:  modalTitle.innerText = 'Documentenuitvoer';
   7:      
   8:  var modalButton = document.createElement('<button class="jqmClose" ></button>');
   9:  modalButton.innerText = 'X';
  10:      
  11:  var modalIFrame = document.createElement('<iframe id="jqmContent" class="jqmIFrame" frameborder="0" scrolling="no"></iframe>');
  12:  titleDiv.appendChild(modalButton);
  13:  titleDiv.appendChild(modalTitle);
  14:      
  15:  modalDiv.appendChild(titleDiv);
  16:  modalDiv.appendChild(modalIFrame);  
  17:      
  18:  body.appendChild(modalDiv);

Listing 4

As you can read in listing 4 first I get the body element and assign it to the 'body' variable. Than I create two div elements, the reason I do not create a div element and use setAttribute to set the attributes, but create the element in one line using a string containing the whole tag is that I could not get it to work, again let me know if you do! The first div will be our modal window. The second with id 'jqmTitle' is the header. Next I Create a span that will contain the text for the header, a (close) button that will be placed in the header on the right side.
And an iframe, in this iframe any (custom) page can be loaded.

INITIALIZE MODAL WINDOW USING jQUERY
To initialize the modal window, we have to add listing 5 to the OnLoad function of the details form in CRM after listing 4.

   1:  $().ready(function() {
   2:    $('#dialog').jqm();
   3:    $('#dialog').jqm().jqDrag('#jqmTitle'); 
   4:  });

Listing 5

In Listing 5 we use jQuery syntax. We attach the code to the OnReadyState eventhandler of the document. when the document is fully loaded the element with id 'dialog' will be registered as a jqModal window by line 2. Line 3 registers the dragging functionality of the element with id 'jqmTitle' inside the modal window (our header div).

CUSTOMIZE ISV.CONFIG XML
Now we only have to do two more things, the first is that we have to change isv.config.xml to create the button on our detail form, I use the contact and need the modal window functionality on the contact entity's form. I made the following change to the isv.config.xml:

   1:  <!-- Microsoft Customer Relationship Management Entities (Objects) -->
   2:  <Entities>
   3:      <Entity name="contact">
   4:        <MenuBar>
   5:          <CustomMenus>
   6:            <Menu>
   7:              <Titles>
   8:                <Title LCID="1043" Text="Documenten" />
   9:              </Titles>
  10:              <MenuItem JavaScript="ShowModalWindow();">
  11:                <Titles>
  12:                  <Title LCID="1043" Text="Plaats document in DocumentUitvoer" />
  13:                </Titles>
  14:              </MenuItem>
  15:            </Menu>
  16:          </CustomMenus>
  17:        </MenuBar>
  18:      </Entity>
  19:  </Entities>

Listing 6

Listing 6 displays part of the xml, the IsvConfig element holds an element configuration , which holds the Entities element. I need the contact Entity. The MenuBar element holds CustomMenus, which holds Menu. I added a Menu element with Title "Documenten" (LCID="1043" which means dutch). The Menu element holds MenuItem elements. I added a MenuItem element With a dutch Title and a JavaScript attribute that has the value 'ShowModalWindow()'. When we import the isv.config.xml and publish the customization changes, we see the menuitem is added.

CREATE JAVASCRIPT FUNCTION THAT SHOWS MODAL WINDOW 
In listing 1 on line 19 we saw that the external javascript file 'customscript.js' is loaded in the OnLoad function of the details form. 'customscript.js' is a custom  javascript file that holds the 'ShowModalWindow()' function.
As I mentiod earlier we had to do 2 more things, the first was the customization of the isv.config.xml and the second is to create this function: 

   1:  var customPagesVirtualDir = 'Custompages';
   2:   
   3:  function ShowModalWindow()
   4:  {
   5:      var contactId = crmForm.ObjectId;
   6:      var popUpUrl = '/' + customPagesVirtualDir + '/Popup.aspx?contactid=' + contactId;
   7:      $('#jqmContent').html('').attr('src', popUpUrl);
   8:      $('#dialog').jqmShow({modal: true});
   9:  }

Listing 7

Addition:  

I added line 1 after Imane pointed out the variable customPagesVirtualDir was not declared, thanks for telling me!

Listing 7 displays the 'ShowModalWindow()' function, the crmForm.ObjectId is assigned to a variable contactId. A variable popupUrl is filled with the url to a custom aspx page. Line 7 is jQuery syntax and assigns the url to the src attribute of the iframe inside the modal window. Line 8 opens the modal window and assigns true to the modal property, So the behaviour of the dialog will be like a modal dialog.

EXAMPLE

CRM's detail form contact entity
Picture 1: Contact details form

In the menu a button is added:


Picture 2: Menu item

 When a user clicks on the menu-item, the function ShowModalDialog is called in the external js file that is referenced in the OnLoad function of the page where the jQuery plugin loads the modal window (client-side!) and the users sees picture 3:

jQuery and jqModal in action on a contact details form
Picture 3: jQuery and jqModal in action on a contact details form

CONCLUSION
Personally I think this is awsome, jQuery is real easy to use and complex matters seem simple. It is a joy to use jQuery with CRM. This combination opens up a world of possibilities. Ofcourse CRM is a web application and customizable, so you could expect external libraries targeted to web applications to work with it. But for me the experience to open a modal dialog like this on a CRM details window without hacking CRM code...
Well I will stop rambling, you can judge yourself.

Henry Cordes
My thoughts exactly...

Currently rated 3.8 by 16 people

  • Currently 3.75/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

CRM 4.0 Login failes 'key expired'

Published 7/24/2008 by Henry in CRM

On our CRM 4.0 Dev environment we experienced the following behaviour:
When opening CRM this message appeared:

The key specified to compute a hash value is expired, only active keys are valid.  Expired Key : CrmKey...

After searching on the machine I found that the Async service did not run, I started it and this solved the issue.

Henry Cordes
My thoughts exactly...

Currently rated 4.8 by 5 people

  • Currently 4.8/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

CRM 4.0 Workflow Wait condition bug

Published 6/30/2008 by Henry in CRM
Tags:

While testing a workflow in CRM 4.0 we encountered the following situation.
The workflow runs when a custom entity is assigned to a person.
In this workflow a wait condition waits until a particular task is completed (activitystatus is completed).
The workflow never stops waiting, even when the task is completed.

You can imagine this is really annoying, I did a support call at Microsoft and after checking some settings, they told us this was a known issue and the were working on the fix.
A few days later we got the fix (KB951919), it is not in the public list of all CRM 4.0 updates and hotfixes, but there is a fix if you need it, just contact MS.

Henry Cordes
My thoughts exactly

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

External js file and CRM

Published 5/27/2008 by Henry in AJAX | CRM | Javascript

While doing a project where MS Dynamics CRM  is used a lot of customizations are performed by JavaScript.
Usually the way to it is to perform some JavaScript actions in the OnLoad of the Page.
MS Dynamics CRM has a extention point, where you can control the OnLoad of Detail Forms by entering JavaScript.

Now when you need to deploy your CRM configuration to more than one system (like we do at my project, it is sold as part of a product), you want to use a centralized Javascript file so you can change your url's etc. all in one place.
To do this (unsupported by Microsoft!) I learnt the following technique from CRM Specialists:

First technique

   1:  var script = document.createElement('script');
   2:  script.language = 'javascript';
   3:  script.src = '/_customscript/customscript.js';
   4:  script.onreadystatechange = OnScriptReadyState;
   5:  document.getElementsByTagName('head')[0].appendChild(script);
   6:   
   7:  function OnScriptReadyState()
   8:  {
   9:      if (event.srcElement.readyState == 'complete')
  10:     {
  11:          // Perform onload script
  12:          //Doit();
  13:      }
  14:  }

Listing 1

The drawback with this technique is that the first time CRM loads (and every time the cache is empty) the script is not executed. Leaving the user to think the application does not work. After some time it really annoyed me, so I started to ask uncle Google again for a solution. I found the following on http://blog.odynia.org/archives/1-Javascript-Includes.html.

What this guy does is doing an AJAX call, to get the js file.
Next he loads the javascript as a string, eval() it, and imports all functions found into the current namespace, so you can access them.

It needs functionnames a-z, it cannot handle numeric values in the name of the function, but i will fix this before I will use it.
Otherwise I think it rocks! Async technique (no first time drawback)

   1:  function load_script (url) 
   2:  { 
   3:      var x = new ActiveXObject("Msxml2.XMLHTTP"); 
   4:      x.open('GET', url, false); 
   5:      x.send(''); 
   6:      eval(x.responseText); 
   7:      var s = x.responseText.split(/\n/); 
   8:      var r = /^function\s*([a-z_]+)/i; 
   9:      for (var i = 0; i < s.length; i++) 
  10:      { 
  11:          var m = r.exec(s[i]); 
  12:          if (m != null) 
  13:          {
  14:              window[m[1]] = eval(m[1]); 
  15:          }
  16:      } 
  17:  } 
  18:   
  19:  load_script("/_customscript/customscript.js"); 
  20:   
  21:  //perform onload scripts
  22:  //DoIt();

Listing 2

Addition:

As I mentioned numbers in the functionname caused the code to fail. So I changed the regex pattern in line 8 from listing 2 into:

   1:  var r = /^function\s*([a-zA-Z_0-9]+)/i; 

Listing 3

With this regex pattern functions with numbers in the name also are added to the namespace. I added the uppercase A-Z not because functions with uppercase characters in the name where not added, but as a best practice. also you can never be sure browsers keep on using IgnoreCase as default setting.

As you can read in the comments, Marc-Andre uses the following pattern:

   1:  var r = /^(?:function|var)\s*([a-zA-Z_]+)/i; 

He wants some vars (which he uses as constants) to be added to the namespace also, maybe I would add the 0-9 here also. anyway, I think it is a good suggestion to mention here.

Addition 2:

Steve Le Mon made a very good suggestion and tried out a few things, he found a way around the parsing of the functions and/or vars and adding them to the current namespace.
I tweaked his code a little bit and ended up with the following:

   1:  function InjectScript(scriptFile)
   2:  {
   3:      var netRequest = new ActiveXObject("Msxml2.XMLHTTP"); 
   4:      netRequest.open("GET", scriptFile, false); 
   5:      netRequest.send(null); 
   6:      eval(netRequest.responseText); 
   7:  }
   8:   
   9:  InjectScript('/_customscript/customscript.js');
  10:   
  11:  //CallFunctionInExternalFile(); 

Listing 4

This technique removes the overhead of the parsing of the functions and vars so will perform faster.

Henry Cordes
My thoughts exactly...

Currently rated 4.9 by 7 people

  • Currently 4.857143/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

The requirement is:
When a user clicks on a form's tab in a Crm detail form, a record needs to be entered into an (Oracle) database. In case of success show a webpage from a particular url (to an application that reacts to the data in the record), in case of failure show a message.
The most elegant way to react to the onclick event of the Tab, in my opinion is to attach to this event in Javascript, ofcourse it is important not to interfere with the attached handler that is already present and takes care of the showing/hiding of the tab's content.

First I took the IE Developer Toolbar, and with the 'Find' > 'Select Element by Click' functionality, I reduced the Tab's id: 'tab4Tab'.
In the Onload handler, of the Form.Properties I added this:

   1:  var tabVar= crmForm.all.tab4Tab; 
   2:  if(typeof(tabVar) != "undefined" && tabVar != null) 
   3:  { 
   4:       crmForm.all.tab4Tab.attachEvent('onclick',insertRecordAndRedirect, false)
   5:  } 
Listing 1

First the tab object with id: 'tab4Tab' is put into a variable called 'tabVar'.
When this variable is not null and not 'undefined', the function called: 'insertRecordAndRedirect' is attached to the onclick of the 'crmForm.all.tab4Tab' object.

So the function 'insertRecordAndRedirect' is called, the moment the Tab with id: 'tab4Tab' is clicked.
This function is also inserted in the Onload handler, of the Form.Properties (like listing 1):

   1:  function insertRecordAndRedirect()
   2:  {
   3:      var id = crmForm.objectId.value;
   4:      document.all.IFRAME_CrmTab.src ='http://www.henrycordes.nl/?tag=/'+id;
   5:  }
Listing 2

The function reads the value (a Guid) from the objectId property of the crmForm object (the UniqueIdentifier of the database record, from which the details are shown in the form). The aspx page that is called takes care of the inserting of the record into the database, using the provided querystring parameter.

In my case, this works really good, and it also solved an issue I had with GoogleMaps and LiveMaps. Because the tabs on which I put the maps are invisible when the form loads, the maps do not seem to know how big they are.

The result is:

  • In the case of GoogleMaps that the center of the map (the chosen spot on the map is centered) always was on (0,0). Left=0, top=0. When using the 'onclick of the Tab' approach, the map is loaded when the tab is clicked, so the map is visible and the map is centered as intended.
  • In the case of LiveMaps, only the right, lower corner of the map was visible in the left, upper corner of the iframe. But when using the 'onclick of the Tab' approach, the map is loaded when the tab is clicked and the map is completely visible and centered as intended.

Henry Cordes
My thoughts exactly...

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

CRM 4.0 Workflows don't start

Published 4/1/2008 by Henry in CRM
Tags:

In CRM 4.0 the MS CRM Workflow Service is not available anymore. CRM 4.0 has one Async Service the 'Microsoft CRM Asynchronous Processing Service'. The Microsoft CRM Asynchronous Processing Service takes care of all asynchronous processess that run within CRM like Workflow and Plugins (former Callouts). 

The Microsoft Dynamics CRM system architecture can be divided into 3 major components: the core system, which features the event execution pipeline, the database component, which hosts the asynchronous queue, and the asynchronous service. One benefit of the scalable architecture of Microsoft Dynamics CRM is that the asynchronous service can be hosted on servers other than the Microsoft Dynamics CRM server. This distributed processing capability can result in improved performance of Microsoft Dynamics CRM.

At a client I work on a CRM 4.0 system, my help was asked when updated workflows (from CRM 3.0 to CRM 4.0) that worked in CRM 3.0 did not work.
I soon came to the conclusion that the workflows did not even started. First I tried changing the executing identity on the service, which did not change anything.

After googling I found that lots of people had this problem and that the problem always was related to the MS CRM Website running with a hostheader, or second ip-address.
After trying out several different options my conclusion is that: 

CRM 4.0 needs to run without a hostheader and with the IP-address option 'All unassigned' chosen.
So you cannot use another IP-address and you cannot use hostheaders (if you want the workflow to function)!

I already found out that the CrmDiscoveryService Web service under the hood uses the machinename to connect to the CRMService and the MetadataService, when I tried to register a Plugin using the PluginRegistration Tool.
Which in itself is remarkable IMHO, the reason for a DiscoveryService is, I think, to decouple these services, which is rather hard if you can only connect using the machinename.

Anyway, if you got this issue make sure you use the following settings (the TCP port is not important in this case, you can use 5555 or 80 or another port):

IIS Website settings for MS CRM 4.0 website, assing no ipaddress and do not use hostheader
All unassigned without hostheader

Henry Cordes
My thoughts exactly...

Currently rated 3.7 by 3 people

  • Currently 3.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

CRM 4.0 Plug-in Developer Tool Extended

Published 2/14/2008 by Henry in CRM
Tags:

I am in the process of developing CRM 4.0 Plugins. This is very different from the formerly known Callouts.
One of the differences is that these assemblies can be deployed to the database, they need to be registered inside CRM.  When plug-ins are registered in Microsoft Dynamics CRM, they become part of the primary operation of the CRM system. Which is different from CRM 3.0 also.
The object model is different, now the assembly must implement the IPlugin interface that lives inside the Microsoft.Crm.Sdk assebmly that comes witk the CRM 4.0 SDK.

Registering the Plugin is done by using API's provided by the CRM 4.0 SDK. The SDK provides the (C#) sourcecode that compiles into a Windows Forms Application that calls these API's to register a Plugin.
With this tool you can register the plug-in on disk or in the database. Here a screenshot from the mainform of that application the 'Plugin Registration Tool for CRM 4.0': 

CRM 4.0 Plugin Developer Tool
Plugin Registration Tool for CRM 4.0

While struggling with this process, I stumbled on the next tool:
http://blogs.msdn.com/crm/archive/2008/02/04/crm-registering-plug-ins-made-easy.aspx

This tool is more complete than the 'Plugin Registration Tool for CRM 4.0' provided as sample code with the SDK. It is developed by the Microsoft Dynamic CRM Team.

New and re-engineered PluginRegistration tool
New and re-engineered PluginRegistration tool


The team addressed 3 core scenarios with this tool.

  1. Developer Scenario:
    An ISV creates a plug-in and registers it on Contact Create as PreCallout (Aka BeforeMainOperation Plug-in). He can then debug the plug-in by registering on Disk. Once the errors are fixed, he can then update the pluginassembly to be uploaded to the database.
  2. Deployment Scenario:
    An ISV builds few plug-ins and registers on multiples steps. Images are registered on few of them. He tests them in the Dev environment but would like to port the registrations to a different organization. PluginRegistration tool supports Export and Import of the solution xml to solve this scenario.
  3. Admin Console:
    Couple of ISV installs their plug-ins on a Customer Organization. Admin at the Customer side saw some problems with “Contact Create” action. He would like to know what plug-in are fired and what the pipeline is for the “Contact – Create”. He then finds the trouble causing plug-in and disables it. So it is all about troubleshooting. PluginRegistration tool solves this problem by allowing Enable/Disable/Unregister operations on steps, plug-in.

The "New and re-engineered PluginRegistration tool" as the team calls it themselves on their blog can be found on code.msdn.microsoft.com here: http://code.msdn.microsoft.com/crmplugin/Release/ProjectReleases.aspx?ReleaseId=90

Henry Cordes
My thoughts exactly....

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Adding new custom entity to CRM 3.0 fails

Published 1/16/2008 by Henry in CRM
Tags:

While we went in production a few requirements were added to our CRM 3.0 project. The last thing we did before going into production was adding and removing roles and teams.

All system roles accept System Administrator where removed, only custom roles where needed, als teams where added. Because of the new features a new (custom) entity needed to be created. When I saved it the following message appeared:
"An error has occurred. For more information, contact your administrator" (talking about a meaningfull error message!).
While I tried to solve this problem I found out Microsoft has a hotfix available for this problem (http://support.microsoft.com/kb/936204/EN-US/). This hotfix can only be obtained through a support ticket from MS Support. In this blogpost is stated that the deletion of the 'System Customizer Role' does the damage.

It has a reference to this KB Article (Microsoft KB article 934690):
When a custom entity is created, Microsoft Dynamics CRM automatically grants the System Customizer role access to the new entity. If you delete or edit the System Customizer role, you receive the error message that is mentioned in the "Symptoms" section.
The blogpost states it appears that when creating a custom entity CRM checks if the 'System Customizer' role is present (at least the if a role with a RoleID equal to the Guid this role had when CRM was installed). Also just manually recreating a "System Customizer" role does not fix the problem.

The solutions present at that moment in time:

  • MS Hotfix
  • Fresh install of CRM with data migration (back up CRM, uninstall CRM, install CRM fresh and then migrate all of your data from the back up into the new system)

Now I really wanted to know what's going on, so I hooked up a trace with SQL Server's profiler. A lot of stored proc calls are made, but just before the first ROLLBACK this dynamic SQL was executed:

   1:  exec sp_executesql N ' select role.RoleId as ''roleid'',role.BusinessUnitId as ''businessunitid''
   2:  from Role as role inner join BusinessUnit as rolebusinessunitid
   3:  on (role.BusinessUnitId = rolebusinessunitid.BusinessUnitId) and rolebusinessunitid.DeletionStateCode in (0)
   4:  and (rolebusinessunitid.ParentBusinessUnitId is null )
   5:  inner join SystemUser as businessunitorganizationid
   6:  on (rolebusinessunitid.OrganizationId = businessunitorganizationid.OrganizationId)
   7:  and businessunitorganizationid.DeletionStateCode in (0)
   8:  and (businessunitorganizationid.SystemUserId = @P1)
   9:  where role.DeletionStateCode in (0)
  10:  and (role.RoleTemplateId = @P2)',N'@P1 uniqueidentifier,
  11:  @P2 uniqueidentifier','X1X1X1X1-Q1Q1-Q1Q1-Q1Q1-X1X1X1X1X1X1','Z2Z2Z2Z2-Y2Y2-Y2Y2-Y2Y2-Z2Z2Z2Z2Z2Z2'
Listing 1

When I ran it in the  SQL Server Manager's Query Window an empty row was returned. 
The following part of the SQL is interesting in this case:

(role.RoleTemplateId = @P2) 
Listing 2

Maybe this could be the Guid that is absent. When we look inside the RoleTemplateBase table we see that all system roles exist in this table, even though they do not exist as roles in this CRM implementation anymore.
When a new entity is created CRM checks to see if the executing user is a member of any role that has a relation to the template with the RoleTemplateId of the 'System Customizer' role template. This to me is strange behavior, specially because the RoleTemplateBase table has no field or relation to the settings of a Role, the only fields it has are:

  • RoleTemplateID;
  • Name;
  • Version;
  • Upgrade.

'RoleTemplateBase' table of the '<organization>_MSCRM' database  
'RoleTemplateBase' table of the '<organization>_MSCRM' database

I used the MS CRM Role Utility to export the System Customizer role to a xml file from a shadow VPC that still contained the role. Als with the MS CRM Role Utility I imported the role into CRM. Here is a link: Systeemaanpasser.xml (31,23 kb) to the xml containing the role (NOTE this is a Dutch CRM installation!, I will try to post an English version of the 'System Customizer' role also).
So the role is in  the system again, now I ran a somewhat customized version of the Dynamic SQL, so it is not dynamic anymore. Figuring when it returns a row this error will be gone.

Query:

   1:  select role.RoleId as 'roleid',role.BusinessUnitId as 'businessunitid' 
   2:  from Role as role 
   3:  inner join BusinessUnit as rolebusinessunitid 
   4:  on (role.BusinessUnitId = rolebusinessunitid.BusinessUnitId) 
   5:  and rolebusinessunitid.DeletionStateCode in (0) 
   6:  and (rolebusinessunitid.ParentBusinessUnitId is null ) 
   7:  inner join SystemUser as businessunitorganizationid 
   8:  on (rolebusinessunitid.OrganizationId = businessunitorganizationid.OrganizationId) 
   9:  and businessunitorganizationid.DeletionStateCode in (0)  
  10:  and (businessunitorganizationid.SystemUserId = 'X1X1X1X1-Q1Q1-Q1Q1-Q1Q1-X1X1X1X1X1X1')  
  11:  where role.DeletionStateCode in (0)  
  12:  and (role.RoleTemplateId = 'Z2Z2Z2Z2-Y2Y2-Y2Y2-Y2Y2-Z2Z2Z2Z2Z2Z2') 
Listing 3

I ran the query and it returned nothing:

Empty result of query
Empty result

I opened the 'RoleTemplateBase' table, selected the row containing the 'System Customizer' role and copied the Guid in the 'RoleTemplateID' field to the clipboard.
Than I opened the Role view (remember 'Select ... from Role as role') and searched for the row containing the newly added 'System Customizer' role.

Records in 'Role' view 
Records in 'Role' view

In this row I pasted the Guid (I earlier had copied to the clipboard) into the field 'TemplateRoleID' and saved it.
Than I ran the query again, but now it returned a row:

Result: "one row"
Result: "one row"

I tried to add a new custom entity into CRM and guess what it worked again!
So the advice I read in a few CRM related blogposts to never remove system roles (specially the 'System Customizer' role) is repeated here in this post.

Henry Cordes
My thoughts exactly...

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

CRM 4.0 SDK available

Published 1/5/2008 by Henry in CRM
Tags:

Well, Titan  (MS CRM 4.0) production release is available  (as 90 day trial)  for download.
Today I learned that the CRM 4.0 SDK is available also, it can be downloaded here.

The CRM SDK does help a lot when customizing a CRM implementation. It has documentation, references, best practices and code samples. I really am happy that it is out and available for us.
I will be involved in a migration project from a CRM 3.0 to CRM 4.0 so maybe will post some more on CRM 4.0 in the near future.

The CRM 4.0 90 day trial versions can be downloaded here.
There are three versions available:

  • Workgroup
  • Professional
  • Enterprise

Within the 90 day trial you can upgrade to a licensed product anytime, you just enter a valid license-key.
After the 90 day period, no warning is given, the product just stops working. When a valid license-key is sentered, the  product will normally continue to work as a licensed product.

Henry Cordes
My thoughts exactly...

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5