Hi all,
This was by no means something I discovered myself, Patrick Verbeeten suggested this as a solution to a problem I had in the forums. I thought it would be a good idea to pass on the information though.
Lets say you have a DynamicEntity object and you need to clear one of the values in a plugin, for example the parentid of a contact. Normally, to add an attribute to a DynamicEntity you would use the entity.Properties.Add(...) method, but the problem is that CRM only processes values that has a value.
What I tried initially was to remove the value using the entity.Properties.Remove(attributename) method. This did delete the attribute, but on saving the DynamicEntity, it did not save this attribute to the server but instead left it the way it was.
What Patrick suggested was to use the null value coupled with each crm attribute type, example CrmDateTime.Null or CrmNumber.Null. So what I did was to add the null value to the PropertyBag and set the acctual value to null.
entity.Properties.Add(new CrmDateTimeProperty(CrmDateTime.Null));
What is very important here is that each attribute type has it's own Null value, you cannot interchange CrmDateTime.Null and CrmNumber.Null.
The only exception to this seems to be a string type attribute, you only need to assign the value as an empty string "". Note that you may also be able to use the String.Empty method, I have not tried this yes but would say that this should also work.
Thanks
Paul Reyneke
Monday, 28 July 2008
Thursday, 12 June 2008
Decrypting the Soap Exceptions thrown by CRM 4.0
I know this has been covered a million times before, but for those new to CRM, here's how to get around the unhelpful soap exception "Server was unable to process request".
Make sure you catch the soap exception, not just the standard System.Exception, this will open up an object called Details that has a property called InnerText. This will give you some more information surrounding the actual cause of the exception. But make sure you catch the System.Exception too, just in case.
So:
try
{
...
}
catch (System.Web.Services.Protocols.SoapException ex)
{
throw new InvalidPluginExecutionException(ex.Message+", "+ex.Detail.InnerText);
}
catch (System.Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
Have fun,
Bossie
Make sure you catch the soap exception, not just the standard System.Exception, this will open up an object called Details that has a property called InnerText. This will give you some more information surrounding the actual cause of the exception. But make sure you catch the System.Exception too, just in case.
So:
try
{
...
}
catch (System.Web.Services.Protocols.SoapException ex)
{
throw new InvalidPluginExecutionException(ex.Message+", "+ex.Detail.InnerText);
}
catch (System.Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
Have fun,
Bossie
Wednesday, 4 June 2008
Steps to isolate why a plugin is not firing
Hi,
This list is more for myself, but other people may benefit from it too. I am compiling a list of steps to go through if a plugin is not firing. This really only covers problems with your assembly being loaded, if the plugin does actually execute some of your code then this will not help you. This list will grow in time as more common pitfalls are uncovered. So check back regularly.
1. Is the assembly signed?
2. Does the assembly reference an external assembly (perhaps an assembly that stores all your common code)? If this is the case, the 2 (or more) assemblies needs to be merged using IL Merge. George wrote an extensive explanation of this here http://crm.georged.id.au/post/2008/02/22/Packaging-plugins.aspx.
3. In the plugin registration tool, did you misspell the step message and entity?
4. Are you trying to reference a pre-image on Create or a post-image on Delete? Neither of these will be accessible and your plugin will fail before it even tries to execute any code.
5. Did you install the assembly to disk? If so you need to make sure you copy the assembly to the assembly\bin directory. The assembly gets loaded from this location every time it is initialized if it is installed to disk.
6. Is this crm server an upgrade form CRM3 to CRM4 or are you still using CRM3 style callouts? It seems that old style callouts get called before plugins, so ensure that there are not any failing callouts in the assembly\bin\callout.config file.
That's it for now, more to follow
Thanks
Bossie
This list is more for myself, but other people may benefit from it too. I am compiling a list of steps to go through if a plugin is not firing. This really only covers problems with your assembly being loaded, if the plugin does actually execute some of your code then this will not help you. This list will grow in time as more common pitfalls are uncovered. So check back regularly.
1. Is the assembly signed?
2. Does the assembly reference an external assembly (perhaps an assembly that stores all your common code)? If this is the case, the 2 (or more) assemblies needs to be merged using IL Merge. George wrote an extensive explanation of this here http://crm.georged.id.au/post/2008/02/22/Packaging-plugins.aspx.
3. In the plugin registration tool, did you misspell the step message and entity?
4. Are you trying to reference a pre-image on Create or a post-image on Delete? Neither of these will be accessible and your plugin will fail before it even tries to execute any code.
5. Did you install the assembly to disk? If so you need to make sure you copy the assembly to the assembly\bin directory. The assembly gets loaded from this location every time it is initialized if it is installed to disk.
6. Is this crm server an upgrade form CRM3 to CRM4 or are you still using CRM3 style callouts? It seems that old style callouts get called before plugins, so ensure that there are not any failing callouts in the assembly\bin\callout.config file.
That's it for now, more to follow
Thanks
Bossie
Tuesday, 3 June 2008
Pre and Post Images
Hi all,
I am probably stating the obvious here, but it does seem to be a recurring theme accross the forums, so I decided to post this.
When the plugin action is a Create then you can only have a Post Image because Pre Image does not exist.
When the plugin action is a Delete then you can only have a Pre Image because the Post Image does not exist.
If you try to use a Pre Image on Create or a Post Image on Delete the plugin will fail before it even reaches your code.
In all the rest you should be able to have both the Pre and Post Images available.
Thanks
Bossie
I am probably stating the obvious here, but it does seem to be a recurring theme accross the forums, so I decided to post this.
When the plugin action is a Create then you can only have a Post Image because Pre Image does not exist.
When the plugin action is a Delete then you can only have a Pre Image because the Post Image does not exist.
If you try to use a Pre Image on Create or a Post Image on Delete the plugin will fail before it even reaches your code.
In all the rest you should be able to have both the Pre and Post Images available.
Thanks
Bossie
Thursday, 8 May 2008
crmForm.SetFieldReqLevel throws error when label got renamed
Hi All,
I came accross an interesting little problem today that took me a while to figure out. This happens in CRM4, but I am fairly sure the same will happen in CRM3.
I have a lookup field to contact called nzi_clientid with a label of Client, I want to rename it to Contact under certain conditions but leave it as Client under other other conditions.
To rename a field on a form has been documented online as:
crmForm.all.nzi_clientid_c.innerText = "Client";
The problem is that if you rename the field using this method, the well documented way to make a field required (crmForm.SetFieldReqLevel("nzi_clientid", 1)) does not work, and it throws an error, "Object doesn't support this property or method".
I had to delve into the html to see what was happening. It turns out that using the above method to rename the field label overwrites more than the label. Before the rename the innerHTML looks like this:
The rename replaces this entire xml section with the new name e.g. "Contact". We don't want this because the crmForm.SetFieldReqLevel cannot find the field any longer because the LABEL node has been overwritten and replaced with "Contact".
<TD class=" ms-crm-Field-Normal" id="nzi_clientid_c" title="Client" style="DISPLAY: inline">
Contact
</TD>
Two ways to fix this is to either to a text replace of the word "Client" in the innerHTML and replace it with "Contact", but this is more than the one or two lines and makes it too complicated.
Second way is to overwrite the firstChild with the new label "Contact". This will mean that the original LABEL node still exists, but the img that shows whether the field is required or not, is gone, even though the field is technically still required. Since I analyse the field right after this and set whether it is required or not, this is not an issue for me.
crmForm.all.nzi_clientid_c.firstChild.innerText = "Client";
if (isRequired)
{
crmForm.SetFieldReqLevel("nzi_clientid", 1)
}
else
{
crmForm.SetFieldReqLevel("nzi_clientid", 0)
}
I came accross an interesting little problem today that took me a while to figure out. This happens in CRM4, but I am fairly sure the same will happen in CRM3.
I have a lookup field to contact called nzi_clientid with a label of Client, I want to rename it to Contact under certain conditions but leave it as Client under other other conditions.
To rename a field on a form has been documented online as:
crmForm.all.nzi_clientid_c.innerText = "Client";
The problem is that if you rename the field using this method, the well documented way to make a field required (crmForm.SetFieldReqLevel("nzi_clientid", 1)) does not work, and it throws an error, "Object doesn't support this property or method".
I had to delve into the html to see what was happening. It turns out that using the above method to rename the field label overwrites more than the label. Before the rename the innerHTML looks like this:
The rename replaces this entire xml section with the new name e.g. "Contact". We don't want this because the crmForm.SetFieldReqLevel cannot find the field any longer because the LABEL node has been overwritten and replaced with "Contact".
<TD class=" ms-crm-Field-Normal" id="nzi_clientid_c" title="Client" style="DISPLAY: inline">
Contact
</TD>
Two ways to fix this is to either to a text replace of the word "Client" in the innerHTML and replace it with "Contact", but this is more than the one or two lines and makes it too complicated.
Second way is to overwrite the firstChild with the new label "Contact". This will mean that the original LABEL node still exists, but the img that shows whether the field is required or not, is gone, even though the field is technically still required. Since I analyse the field right after this and set whether it is required or not, this is not an issue for me.
crmForm.all.nzi_clientid_c.firstChild.innerText = "Client";
if (isRequired)
{
crmForm.SetFieldReqLevel("nzi_clientid", 1)
}
else
{
crmForm.SetFieldReqLevel("nzi_clientid", 0)
}
Labels:
crmForm.SetFieldReqLevel,
firstChild,
innerHTML,
innerText,
Object doesn't support this property or method,
SetFieldReqLevel
Monday, 18 February 2008
Reassign a primary entity also reassigns activities.
Hi all,
I have found a little annoying feature on CRM 4.0 (also in CRM3.0) that reassigns all the activities attached to an entity when the entity is reassigned. Now this may not normally be a problem, but consider the following example.
We have three users called Account Manager1, Account Manager2 and Office Admin. Account Manager1 manages an account Account1 and creates a task for Office Admin to do something (e.g. update address details). This task sets the regarding object to be Account1 and the owner to be Office Admin. Now let us assume this Account1 is now reassigned to Account Manager2 by reassigning the account to Account Manager2. Ok, simple stuff so far.
The problem is now that not only does the Account1 get assigned to Account Manager2, but so does this task assigned to Office Admin without any regard for its original owner. This also goes for ALL other activities against Account1, it doesn't matter who the activities were assigned too initially (i.e. the account owner or someone esle), they all get reassigned automatically in a "don't care" fashion.
In this example we do not want the Task assigned to the Office Admin to be reassigned when the parent account gets reassigned.
It seems that the relationship between an activity and its parent entity is parental by default for ALL activities. This can be changed by setting the relationship between the entity and the activity (Account and Taks in this case) to "Configurable Cascading" and setting the drop down for "Assigned" to the required Cascading level.
The main annoyance comes in the fact that it has to be changed for every entity-activity relationship. So assume the basic entities (Account, Contact etc) multiplied by the 8 different types of activities (Task, PhoneCall etc). This means that for a standard project I need to potentially go and change more than 100 relationships (depending on your project usage) to the cascading level required.
I have not found an easier way to do this yet, but will post any updates when I find them
Bossie
I have found a little annoying feature on CRM 4.0 (also in CRM3.0) that reassigns all the activities attached to an entity when the entity is reassigned. Now this may not normally be a problem, but consider the following example.
We have three users called Account Manager1, Account Manager2 and Office Admin. Account Manager1 manages an account Account1 and creates a task for Office Admin to do something (e.g. update address details). This task sets the regarding object to be Account1 and the owner to be Office Admin. Now let us assume this Account1 is now reassigned to Account Manager2 by reassigning the account to Account Manager2. Ok, simple stuff so far.
The problem is now that not only does the Account1 get assigned to Account Manager2, but so does this task assigned to Office Admin without any regard for its original owner. This also goes for ALL other activities against Account1, it doesn't matter who the activities were assigned too initially (i.e. the account owner or someone esle), they all get reassigned automatically in a "don't care" fashion.
In this example we do not want the Task assigned to the Office Admin to be reassigned when the parent account gets reassigned.
It seems that the relationship between an activity and its parent entity is parental by default for ALL activities. This can be changed by setting the relationship between the entity and the activity (Account and Taks in this case) to "Configurable Cascading" and setting the drop down for "Assigned" to the required Cascading level.
The main annoyance comes in the fact that it has to be changed for every entity-activity relationship. So assume the basic entities (Account, Contact etc) multiplied by the 8 different types of activities (Task, PhoneCall etc). This means that for a standard project I need to potentially go and change more than 100 relationships (depending on your project usage) to the cascading level required.
I have not found an easier way to do this yet, but will post any updates when I find them
Bossie
Subscribe to:
Posts (Atom)