CRM Blog

March 2008 - Posts

Various Ways To Hide/Unhide A Field/Section In CRM
by Danny Varghese 03.28.08

Comments    No Comments
Intro

When customizing forms in CRM, one of the most commonly used and simplest things to do is a hide a field on the form.  This may be hiding one or numerous fields on the form.  Often times, developers may need to use several “hidden” fields for other purposes.  In this case, he/she could place all those fields in a section on the form, and then hide the section.

Hiding A Field

To hide a field use the following code snippet:

 crmForm.all.<insert schema name of field>_c.style.visibility = ‘hidden’;crmForm.all.<insert schema name of field>_d.style.visibility = ‘hidden’; 

 

OR

crmForm.all.<insert schema name of field>_c.style.display = ‘none’;crmForm.all.<insert schema name of field>_d.style.display = ‘none’; 

You will have to hide both the “_c” and “_d” parts of the field.  The “_c” appended to the field is the label of the field, and “_d” is the data contained in the field.

Un-hiding A Field 

To un-hide a field, use the following code snippet:

crmForm.all.<insert schema name of field>_c.style.visibility = ‘visible’;

crmForm.all.<insert schema name of field>_d.style.visibility = ‘visible’;

 

OR

 

crmForm.all.<insert schema name of field>_c.style.display = ‘block’;crmForm.all.<insert schema name of field>_d.style.display = ‘block’; 

 

Hiding A Section

 

To hide a section (which will in turn, hide all fields in that section), use the code snippet below:

 crmForm.all.<insert schema name here>. parentElement.parentElement.parentElement.style.display = 'none'; Un-hiding A Section

To un-hide a section, use the code snippet below:

crmForm.all.<insert schema name here>. parentElement.parentElement.parentElement.style.display = 'block';

Filed under:
Differences between the Workflow Functionality from CRM 3.0 to CRM 4.0
by Zahara Hirani 03.26.08

Comments    No Comments

Workflows in CRM 4.0 have a lot more features than those in 3.0 (even some of the lingo is different). So let’s look at the differences.…

For starters, Workflows can now be accessed from any computer that can access CRM, instead of the separate application that could only be run on the CRM server in 3.0. In CRM 4.0, just navigate to the Settings Module and you should see workflows for administration and configuration.

Another key feature is that workflows can now be applied on a user, business unit, parent-child business unit or an organization level. Giving users the ability to create workflows, that are custom to the way they work, is awesome (as long as the security is set up rightJ).

My personal favorite is the ability to trigger a workflow when fields are updated. Yes you read that right – workflows can now be set up to trigger based on the update of fields on the entity.  Also now you can trigger workflows on deletion of an entity record.  Additionally, you can publish a workflow as a workflow or publish it as a template that can be used for other workflows.   Like before, workflows in CRM 4.0 can be set to run on-demand or as child workflows depending on their purpose.

Now let’s dive into the differences in setting up the workflow components. One thing you may have noticed in CRM 3.0 is that actions could only be performed on the primary entity, in CRM 4.0 they can even be performed on related entities. We can go over that in detail in a bit.

In CRM 3.0 you could insert conditions and actions, now they both are grouped together in a step. You can also pick if you want to enter the step before your current step or after the current step. So let’s start!!

Stages

·         In CRM 4.0, there are no sales processes as there were in 3.0, but instead all workflows may have stages. ·         These stages are a part of the workflow steps and can be used to define your sales process or any process that you may want to create, such as a support process.

If Condition

·         The “If” Conditions in CRM 3.0 and 4.0 have stayed the same with the addition of the Default Condition (else statement).
·         One thing I found out the hard way was you can only have 5 nested if statements which is less than what you could in CRM 3.0.

Wait Condition

·         The Wait condition which used to be a part of the Insert Conditions in CRM 3.0 is now a separate step.
·         Also, you can have multiple Wait Conditions (Parallel Conditions) which wait simultaneously for different conditions to go thru.  
·         Wait timers in CRM 3.0 are now a part of the wait condition in CRM 4.0. For the timer, you have to set the duration to the Workflows Timeout Attribute.

Create Record

·         The Steps in CRM 4.0 do have additional functionality when compared to the Actions in CRM 3.0 like now you can create not just activities but system entities as well as custom entities – how cool is that!!  
·         Also, now that Notes are a separate entity, you can use the Create Record for them as well instead of the CRM 3.0 Create Note functionality.

Update Record

·         The update feature in CRM 4.0 is similar to that of CRM 3.0 with one minor change – you can update multiple fields instead of having to update each field one by one .

Assign Record

·         Assigning records in CRM 4.0 has major improvements like now you can assign not just the primary entity but related entities as well. 
·         Additionally, instead of being limited to assigning the entity to just the User, Manager or Queue, you can assign the record to users from related entities. One I recently used was when a case is created; assign the case to the owner of the account. 

Send Email

·         The Send Email functionality in CRM 4.0 is very similar to that of CRM 3.0 with the addition of being able to set the to, from, cc and bcc to dynamic values based on related entities.

Child Workflow

·         Sub processes can be CRM 4.0 like other features can be run not just for the primary entity but related entities as well.

Update Status

·         Update Status is no longer limited to the primary entity as it was in CRM 3.0, now you can update the status for related entities as well.

Stop Workflow

·         Unlike CRM 3.0 where if you wanted to stop the workflow you could select complete, cancel, complete and stop processing other rules and cancel and stop processing other rules; in CRM 4.0 you can only select complete or cancel.

Call Assemblies

·         Call Assemblies also seem way cooler (at least the ones you upgrade from CRM 3.0 to 4.0 do). You can now access the individual attributes of your custom assembly return object. I recently did an upgrade where I had a custom assembly written in 3.0 that returned a system user.  In CRM 3.0 I could only access the system user but not its attributes, but that changed in CRM 4.0J.

A couple of features that no longer exists with CRM 4.0 are the Post URL action and the custom assembly class that allowed for programmatically triggering a workflow process.One thing I did notice was in CRM 4.0 if I added a step and then didn’t save, and pulled up my workflows, my change would still exist even though I didn’t save. Not sure why that happened!!! 

Workflows in CRM 3.0 had to be activated or deactivated; in CRM 4.0 they need to be published or un-published.

In CRM 3.0, if you wanted to look at current workflow logs, you used the Workflow Monitor. Now you jut navigate to the record that triggered the workflow and you should be able to see all system jobs(logs in CRM 3.0) that are currently in progress, cancelled or succeeded. You can open each system job to see what step the workflow has completed or is currently at.

Unlike CRM 3.0 where you have separate applications for importing and exporting workflow, in CRM 4.0 you can import and export using the export/import customizations functionality already a part of CRM.

The one thing (of manyJ) I haven’t figured out is how to copy workflows, in CRM 3.0 it used to be a button click. The workaround I ended up having to use is unpublishing my workflow and changing the ‘publish as’ setting to workflow template and republishing it and then creating a new workflow and using that template.  
Filed under:
Cloning An Entity In CRM
by Danny Varghese 03.26.08

Comments    2 Comment(s)

Intro

We’ve had requests from our clients to “clone” already created records at the click of a button.  The reason is that when users are entering data into numerous records of the same entity every day, where only a few fields may differ, it can be cumbersome.  A great example is we created an entity with over 50 fields and users may create 10-15 records of that entity where 90% field values will be the same.   I’ll explain the approach we took.

Approach

1.       Create a JavaScript function that will open a window to the entity to be cloned to (make the window variable global)

2.       Edit the ISV.config.xml to add a button, and in the configuration, reference the JavaScript function created above

3.     Inside the JavaScript function (you may create other methods as well), call the function to check the status of the new window

4.    When the page is loaded, start mapping from one window to the other as in the second function below

function checkPageState()

{              if (oClonedEntity.document.readyState == 'complete')               {                   cloneEntity();                          return;         }  

  setTimeout('checkPageState()',100);            

}     
function cloneEntity(){            
with(oClonedEntity.document.crmForm)       {             

    //add fields here that you want to copy from one entity to the newly created one

    new_field1.DataValue = crmForm.all.new_field1.DataValue;                  new_field2.DataValue = crmForm.all.new_field2.DataValue;       }                            //finally, close the dialog       

window.close();

} 
5.       After inserting the above code, test it out.  This will be highly beneficial for users, enjoy!

 

Sorting By Multiple Columns In Microsoft CRM
by Danny Varghese 03.25.08

Comments    No Comments

Microsoft CRM views in 3.0 are a great way to view important parts of records in a clear concise manner.  The views also offer sorting which is an even greater plus for many users.  What may not be known however is that users can sort by multiple columns!

Simply hold down the SHIFT key, and viola!  This can be especially helpful for views that have columns with data that have similar values.  A prime example is in CRM, if there are hundreds, or even thousands of Contact records, and the view might have first and last name columns.  The likely hood of having duplicate first names is high.  So if a user wants to sort by first and last names, he/she can hold down the SHIFT key, and click on the first name and last name column. 

Hope this helps!

Converting A CRM Field To A Browse-able File Path Field
by Danny Varghese 03.24.08

Comments    2 Comment(s)

One of the requirements for a client was the ability to “attach” a document to a record in CRM without using CRM built in attachments/notes nor actually attaching the document but rather creating a link to the document.  This is because, when attaching any files using attachments/notes, those attachments are stored on the server and the client already had these files stored in a shared directory on a server.  Recreating these documents within the CRM db would have just been overhead (the data would not be needed when disconnected) and would not have allowed easy updating of the shared document. 

To curb their apprehensions, a senior manager of ours, Bryan Van Antwerp created a customization that allows a field to be converted to a browse-able file path field.  This allowed users to browse to a certain file on the shared network, and “attach” it to a custom entity.  Then whenever the user wants access to that document, he/she would simply open the record up and double click on the path and the document will use Window’s functionality to open/save the document.

The two functions below, written by Bryan Van Antwerp, illustrates this example:

function convertFilePathToFileInputType(fieldName)

{          //variable initialization         var field = null;                                                      var fieldValue = null;                                                        var fieldTabIndex = "";         var fieldMaxLength = "";         var fieldReq = "";         var fieldColSpan = "";                field = document.getElementById(fieldName);         fieldValue = field.value;         fieldTabIndex = field.tabIndex;         fieldMaxLength = field.maxLength;         fieldReq = field.req;         fieldColSpan = document.getElementById(fieldName + '_d').colSpan;       

  if(field.value.length > 0)

  {                   //have value so show text and remove button                                 field.insertAdjacentHTML('afterEnd','<span id="' + fieldName + '_rBSpace">&nbsp;</span><input width=0 height=0 type="hidden" value="Remove" id="' + fieldName + '_removeButton" onClick="removeFilePath(\''+fieldName+'\');"></td>');                   document.getElementById(fieldName).style.width = "100%";             

     document.getElementById(fieldName+'_removeButton').style.width = "0%";

     document.getElementById(fieldName+'_rBSpace').style.width = '0%';                   field.readOnly = true;                   field.className = 'txt ro';                   field.attachEvent('onclick', function(){try{var win = window.open(document.getElementById(fieldName).value);}catch(e){alert("Unable to open file.");}});                     }         else         {                   //do not have value so show file input type                   field.insertAdjacentHTML('afterEnd','<td colspan=' + fieldColSpan + ' id="' + fieldName + '_d"><input type="file" id="' + fieldName + '" tabindex="' + fieldTabIndex + '" maxlength="' + fieldMaxLength + '" class="txt" value="' + fieldValue + '" req="' + fieldReq + '"></td>');             

     document.getElementById(fieldName).style.width = '100%';

     field.parentNode.removeChild(field);         } } function removeFilePath(fieldName){         document.getElementById(fieldName).value="";         var field = document.getElementById(fieldName+"_removeButton");         field.parentNode.removeChild(field);          field = document.getElementById(fieldName+"_rBSpace");         field.parentNode.removeChild(field);      

  convertFilePathToFileInputType(fieldName);     

}

The first function converts the actual field to a browse-able field if there’s no data that exists.  If there is data, the “Remove” button is shown (per requirement of the business), and the field is disabled - also note that there is an event that is attached that when the field is clicked it will open the link.  The second function is called when the “Remove” button is clicked and it removes any values in that field.

Filed under:
Performing Large Data/Record Transactions In Microsoft CRM 3.0
by Danny Varghese 03.20.08

Comments    No Comments
Challenge

Recently a client had asked for custom development that required processing of thousands of CRM records, each with many relationships which all get affected.  Each of those records had large amounts of data that needed to be processed.  This was a huge challenge because we had to allow the user to process these records, yet be able to perform other jobs in CRM.  This is a great case of how robust, powerful and flexible CRM can be.

Solution Attempt #1

The first thing that came to mind was writing a callout. 

Pros:

·         Callouts can be triggered by an update event (along with create, delete, and assign). 

·         Writing code in .NET is relatively inexpensive using object oriented programming principles.

·         Callouts can be programmatically imported and exported and with ease.

·         It provides greater control of how the program is supposed to execute and greater debugging capabilities.

Con:

·         Callouts are synchronous transactions, which means that the user has to wait until the program has finished executing before moving on.  This does not meet one of our requirements.

·         They can be made to be asynchronous by spinning up multiple threads, but caution has to be taken so no deadlocks occur.

Solution Attempt #2

The next thing that came to mind was using a workflow that calls a custom assembly file.

Pros:

·         You can specify certain rules/conditions upfront to fire the workflow.

·         You can call an assembly file which can use the same basic principles of object oriented programming, debugging, etc. that callouts can allow you to use.

·         Can be kicked off by a user when ever he/she needs to by pressing “Apply Rule.”

Cons:

·         We found that with processing thousands of records, sometimes the workflow service would time out causing errors.  The timeout limit  can be set to something really high like 2 hours, but that defeats the purpose of the timeout for most workflows.  Additionally, there may be times when several hours may not be enough time.

·         It’s difficult debugging any issues with the workflow itself.

·         No workflow API is exposed that we can access.

·         Rules cannot be programmatically imported/exported.

Solution Reached!

After much soul searching, and numerous issues with the above two attempts, a happy medium was reached.  We used the workflow service to call an assembly file.  Within the assembly file, we spun up one thread.  This thread then proceeded to execute the rest of the program, but we returned a value back to the workflow service so it “thought” the workflow had finished running.  In reality, there’s a thread in the background processing all the transactions.  This was ideal for this particular business’ need because of the large amount of data that needed to be processed, but also allowing the user to continue working on other things.

Filed under:
Incorporating Custom Entities into a Plugin (revised)
by Mitchell Kett 03.19.08

Comments    3 Comment(s)

Thanks to a reader's comment over my previous post, a small error has been brought to my attention and at the same time gave me an opportunity to improve and even go further into the process of using a custom entity within a plugin.

Microsoft.Crm.Sdk vs. CrmServiceWsdl 

Custom entities cannot be seen by the normal Microsoft.Crm.Sdk since it is a pre-compiled assembly that doesn't keep track of any changes you make to CRM.  Including the web reference to the CrmServiceWsdl (as explained in my previous post) makes all custom entities accessible.  However, it is not necessary to include a "using" statement for that web reference (You'll see why in the code provided later). 

DynamicEntity vs. DynamicEntity

Both the Sdk and Wsdl have their own respective DynamicEntity object, but the correct one to reference/use comes from the Sdk.  After eliminating the "using" statement for the Wsdl, you can declare a DynamicEntity and be assured that it is of type Microsoft.Crm.Sdk.DynamicEntity. 

Improved Code

//Standard references
using System;
using System.Collections.Generic;
using System.Text;
//References added by user
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.SdkTypeProxy;

namespace VehicleNamePlugin
{
    public class VehicleNameHandler : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            DynamicEntity vehicle = null;

            //Check for entity to work with
            if (context.InputParameters.Properties.Contains("Target") &&
                context.InputParameters.Properties["Target"] is DynamicEntity)
            {
                vehicle = (DynamicEntity)context.InputParameters.Properties["Target"];
                //Check to make sure entity is a Vehicle entity
                if (vehicle.Name != VehicleNamePlugin.CrmServiceRef.EntityName.new_vehicle.ToString()) { return; }
            }
            else { return; }

            try
            {
               //Code to execute
               
            }
            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the AccountCreateHandler plug-in.", ex);
            }

        }
    }
}

The above code takes the incoming DynamicEntity and checks to see if it is a new_vehicle (a custom entity created in CRM).  It is a carbon-copy of the code used in the sample plugin written in the SDK with the only change being the bolded text (which uses the Wsdl to grab the EntityName of the custom entity).

Registration

Say we want to fire off this plugin (even though it does nothing at the moment) after a new vehicle is created, but we can't find the new_vehicle within the EntityName list in the Registration Tool.  Luckily the SDK includes easy instructions on how to fix this.

Build the Visual Studio Solution

  1. Open the SDK\Tools\PluginRegistration folder and double-click the PluginRegistrationTool.sln file to open the solution in Visual Studio.
  2. In Solution Explorer, right-click the project name, PluginRegistration, and then click Add Web Reference.
  3. Enter the URL for the CrmService Web service in the form:

    http://<server:port>/mscrmservices/2007/CrmServiceWsdl.aspx

    Use the appropriate server name and TCP port for your Microsoft Dynamics CRM server.

  4. Enter a Web reference name of CrmSdk and click Add Reference.
  5. Repeat steps 3 and 4 for the CrmDiscoveryService Web service. Use a URL of http://<server:port>/mscrmservices/2007/AD/CrmDiscoveryService.asmx and name the Web reference CrmSdk.Discovery.
  6. Repeat steps 3 and 4 for the MetadataService Web service. Use a URL of http://<server:port>/mscrmservices/2007/MetadataService.asmx and name the Web reference MetadataServiceSdk.
  7. Compile the project by clicking Build, and then Build Solution. The executable file can be found in the bin\Debug folder of the project.
  8. If you are building and running the tool on a computer that is not a Microsoft Dynamics CRM 4.0 server, copy the Microsoft.Crm.Sdk.dll assembly from the SDK\Bin folder to the project's bin\Debug folder. The tool requires access to the Microsoft.Crm.Sdk.dll assembly in order to run.

Add the Tool to Visual Studio

You can register the Plug-in Registration Tool as an External Tool for Visual Studio.

  1. Open Visual Studio.
  2. Click on Tools | External Tools and then click on the Add button. If you have not yet added any tools, click on [New Tool 1].
  3. In the Title field, type CRM Plug-in Registration Tool.
  4. In the Command field, click the ellipsis button (…) and navigate to the bin\Debug\PluginRegistration.exe file that you built in the previous task. Click Open.
  5. Click OK.

You have now added the plug-in registration tool to the Visual Studio Tools menu.

Now that you've rebuilt the Plugin Registration Tool, you should now be able to see your custom entities in the EntityName list.  This may only get you started with custom entities and plugins, but it's definitely enough to spark some new ideas.

Filed under:
Adding An IFrame That Contains A View Of Related Entity
by Danny Varghese 03.18.08

Comments    12 Comment(s)
Situation

CRM has out of the box capabilities to add IFrames to entity forms.  These IFrames can allow a user to access any webpage inside of a system or custom CRM form.  The beauty of CRM comes to light here, with the fact that CRM forms are html web based pages, each with its own url.  Developers can take that url, and pass it into the IFRAME, to open up other entities, forms, or even associated views!  This comes in handy when clients don’t want to navigate away from the main screen to see information on related entities.

Example Of Use

For example, say on the Account form, you wanted to see an IFrame that contains an associated view of all activities belonging to that account.  Here are the steps you can take (again, this can be done with any entity):

1.       Under Settings à Customization à Go to entity form, open the form

2.       Add an IFrame to the tab and section you want, specify the name and set the url to “/_root/blank.aspx”

3.       Using JavaScript, add the code below to point the IFrame’s source to a given url.  In this case, the url of a window that has all activities related to a particular account.

var urlAct = ""; urlAct =  "areas.aspx?oId=" + crmFormSubmit.crmFormSubmitId.value + "&oType=" + crmFormSubmit.crmFormSubmitObjectType.value + "&security=" + crmFormSubmit.crmFormSubmitSecurity.value +"&tabSet=areaActivityHistory"; document.getElementById('IFRAME_History').src =urlAct;

4.       The code snippet above creates a url that points to an existing CRM view that has all activities for a given account.  Then it retrieves IFrame element by name (you specified this in step 3), and sets the source to the newly created url.

The result is on the Account form, wherever you placed the IFrame, it will show the view of all activities related to that account.  Again this IFrame can be created for any entity with a relationship to another entity.

Filed under:
Tired Of IISReset? A Possible Alternative.
by Danny Varghese 03.17.08

Comments    No Comments

In Microsoft CRM 3.0, when any changes are made to the ISV.config.xml file, or to any custom assembly files used for callouts, a reset of IIS is needed. To do this a user will need to open the command line, run the command “iisreset,” and then wait until the form/page loads again.  This could get tedious and time consuming if editing a large number of files, or running numerous tests.  There is a shortcut to “iisreset” in CRM, that will work most of the time.  Please note, that this doesn’t take the place of an “iisreset,” and it may not work all the time.  I have seen this work when I’ve made changes to the ISV.config.xml file. 

Go to the root Microsoft CRM folder\CRMWeb and open the global.asax file.  A word of caution, make sure this file is backed up before editing it.  This file is used to declare application level events and objects. This file is compiled upon the arrival of the first request for any resource in the application.  So if any changes were made to this file, it would be compiled on the next request made, redirects all requests to the new compilation.  This “resets” the application in some effect.  Example of use: 

  1. Edit ISV.config.xml file to add a new button
  2. Go to the global.asax file
  3. Open, add a space at the end, save, remove space and save again.
  4. Refresh CRM page, and you should see the new button.
Filed under:
Adding A Button To CRM
by Danny Varghese 03.16.08

Comments    2 Comment(s)

In CRM, it’s widely known that you can add buttons to both system and custom forms.  However, there aren’t too many examples on how to do it, and also some practical examples.  To add a button to a CRM form, you simply need to edit the ISV.config.xml file and then reset IIS. 

Here’s an example on how to add a button on the Account form that when clicked, will open a new internet explorer page to www.microsoft.com.

1.        Go to the following directory where the ISV.config.xml is located: C:\Program Files\Microsoft CRM\CRMWeb\_Resources and back up the file.

2.       Open the file using any xml/text editor (NOTE: Some text editors may cause the xml to get corrupted so be careful.  Ideally an XML editor is recommended).  Add an entry for a new button to the Account toolbar.

a.       <Button ToolTip = “Open Window” Icon =”/<insert relative path>” Title = “Open Window” JavaScript=”window.open(‘http://www.microsoft.com’)”;/>

<ToolBarSpacer/>

3.       In the above example you can see I navigated to the Account entity’s toolbar and created the entry with the following parameters:

a.       ValidForCreate: 0 = button will not show up on a “Create” form. 1 = button will show up on a “Create” form.

b.      ValidForUpdate: 0 = button will not show up on an “Update” form.  1 = button will show up on an “Update” form.

c.       Button ToolTip:  when a user performs a mouse over action on the button, a dialog box will appear with whatever text specified here.

d.      Icon: relative path of the icon used for the button. 

e.      Title: name to appear on the button.

f.        BLOCKED SCRIPT whether to attach a JavaScript code snippet or function to the click on the button.  (NOTE: You can also reference a JavaScript method here that exists in another file, however, that file must be referenced at the onLoad() or onSave() methods of that form)

4.       A new button should now appear on the toolbar and after clicking it, a new internet explorer page opens to www.microsoft.com

Some really neat applications I’ve seen are below:

1.        Add a button on the Account/Contact form that takes the address, sends in the parameters to MapQuest or Google Maps, and pops a window with a map of the location.

2.       Add a button on any form, that when a user clicks, will create an identical copy of that form (Clone function).  This can be useful when entering data numerous times where only a few entries may be different.

3.       Add a button that is a shortcut to the “Apply Rule” menu item in the Action menu.

Error When Creating A New Appointment
by Danny Varghese 03.14.08

Comments    No Comments

One of our clients recently had an issue where a user got an error message when trying to create a new appointment.  Upon saving, a dialog pops up “The record you are requesting is currently unavailable.  Either the record was not found or you don’t have sufficient permissions to view it.”  When getting that message, I thought it was a permission issue, but that was quickly ruled out.  After much searching, I ran across a post on Ronald Lehman’s blog.  He posted the solution to this, but I wanted to reference this as well because our client received it a few times.  Also, it took me quite some time to find this post, so hopefully we can give it more exposure.  The url for Ronald’s blog post is: http://ronaldlemmen.blogspot.com/2007/05/error-when-creating-new-appointment.html. 

Basically he goes on saying that this is caused by an “orphan” record in CRM.  The SystemUserBase table in CRM should have a one to one correlation with the Resource table.  That is if a record exists in the Resource table, but not in the SystemUserBase table (as was our case), then this error would be received.

After running the query he suggested and “cleaning” up the data, that resolved the issue.

Filed under:
Incorporating Custom Entities into a Plugin
by Mitchell Kett 03.14.08

Comments    2 Comment(s)
I'd like to build off of Luke's post from a while back which explained how to create a simple plugin for CRM 4.0.  For those of you who haven't already read his post or seen the simple plugin from the SDK, I highly recommend looking over both to get a real quick but effective rundown of how plugins work.  Just like with the examples before, we'll start with a blank C# project in Visual Studio.  Some things to consider before coding:
  1.  Make sure any and all custom entities are published.
  2. Create the references to Microsoft.Crm.Sdk and Microsoft.Crm.SdkTypeProxy.
  3. Create a Web reference using the url http://localhost:5555/mscrmservices/2007/CrmServiceWsdl.aspx (you can replace localhost:5555 with the appropriate server and port number if different) and give it a name (e.g. CrmServiceRef).
  4. Sign the project and strong-name it by right-clicking on the project in the Solution Explorer and click Properties (Signing should be the bottom tab when the Properties window appears).
For this example I have created a custom entity called "Vehicle" with an entity name of "new_vehicle" in CRM.  I named the web reference "CrmServiceRef" and added it below the other "using" statements as <Project Name>.<Web Ref Name>. With that out of the way we can start coding our plugin:

//Standard references
using System;
using System.Collections.Generic;
using System.Text;


//References added by user
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using VehicleNamePlugin.CrmServiceRef;

namespace VehicleNamePlugin
{
    public class VehicleNameHandler : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            CrmServiceRef.DynamicEntity vehicle = null;
                        //Check for entity to work with
            if (context.InputParameters.Properties.Contains("Target") &&
                context.InputParameters.Properties["Target"] is CrmServiceRef.DynamicEntity)
            {
                vehicle = (CrmServiceRef.DynamicEntity)context.InputParameters.Properties["Target"];
                //Check to make sure entity is a Vehicle entity
                if (vehicle.Name != CrmServiceRef.EntityName.new_vehicle.ToString()) { return; }
            }
            else { return; }
                        try
            {
               //Code to execute
            }
            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the AccountCreateHandler plug-in.", ex);
            }
       

        }
    }
}

The bolded text points out the key differences between working with standard entities and custom entities in a plugin.  Notice that the majority of the code isn’t new (Could be taken straight from Luke’s example), until we get to the declaration of the DynamicEntity.  The web reference that we use actually encompasses almost everything within the Microsoft.Crm.Sdk package, so it is necessary to explicitly tack on "CrmServiceRef" to a number of things (e.g. DynamicEntity).  If you fail to do so, you will get one or both of the following errors when you try to build:
  1. '<Object Name>' is an ambiguous reference between 'Microsoft.Crm.Sdk.<Object Name>' and '<Project Name>.<Web Ref Name>.<Object Name>'
  2. Cannot implicitly convert type 'Microsoft.Crm.Sdk.<Object Name>' to'<Project Name>.<Web Ref Name>.<Object Name>

It is necessary to keep both references, though, since the IPlugin class falls within the Sdk and not the web reference.

One thing to keep in mind: You should regularly update the web reference by right-clicking on it in the Solution Explorer in order to make any changes you’ve made to custom entities visible.Aside from those differences, including a custom entity into a plugin is relatively painless (even though it took quite a while to figure it out in the first place).
Filed under:
Using Windows “Copy To Clipboard” Functionality In CRM
by Danny Varghese 03.12.08

Comments    No Comments

Using The Clipboard

A really neat use of creating a button in Microsoft CRM is using the Windows “copy to clipboard” functionality.  Many of our clients have asked for a button on the Account and Contact forms that would, on click, copy all the address information to the Windows clipboard so that they could paste it in e-mails, documents, notes, etc.  Here’s how to do it:
  1. Edit the ISV.Config.xml file to add a button to the Account and Contact forms.
  2. Add a “JavaScript” parameter to the button configuration to, using good programming practices, call a JavaScript method that exists in a single file location.  This is so that both any number of entities can access the same method in one place.
  3. Write a JavaScript function to build a string that you want to be copied to the clipboard.
  4. Pass that into the function I created below, that calls the windows copy to clipboard function:
function copyTextToClipboard(textToCopy){             if (textToCopy != null)             {                        //copy data to windows clipboard                           if (window.clipboardData)                       

   {

       window.clipboardData.setData("Text", textToCopy);             

   }

 }

} Shortfalls

The windows clipboard does have a few shortfalls:

1.       Each time you copy, the data does replace whatever the old one was

2.       Each string copied does not carry over to other sessions

3.       You can’t easily preview the copied string

4.       Only one string can be stored at a time.

Filed under:
Server Was Unable To Process Request - Generic Error Message
by Danny Varghese 03.11.08

Comments    2 Comment(s)

Issue

Often times, developers see the generic error message “server was unable to process request” that gets thrown when executing a callout in Microsoft CRM 3.0.  This message is a generic message that gets thrown to the windows event log.  Unfortunately, diagnosis of the actual problem can be very difficult from these types of messages. 

How To Diagnose A Bit Better

The best way, I’ve found is to trap this type of exception in your code, and print out the message, stack trace of the exception and the “inner exception.”  The specific exception thrown in this case is the System.Web.Services.Protocols.SoapException (http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.soapexception.aspx).  The “outer exception” contains the “server was unable to process request” exception, but the “inner exception” contains a more detailed description (NOTE:  sometimes the inner exception may not be descriptive enough, but it should point you in the right direction).  An example of an inner exception would be “object not set to a reference,” which often times indicates trying to perform an action on a null object.

Code Snippet

Below is an illustration of how to trap that exception and print it out.

try

{

     //do something here

}

catch (SoapException se)

{

     Console.WriteLine(se.Message + “ “ + se.StackTrace);

     Console.WriteLine(se.InnerException.Message + “ “ + se.InnerException.StackTrace);

}

Filed under:
Customer Address - Error When Creating New Via Web Services
by Danny Varghese 03.10.08

Comments    4 Comment(s)
Issue

I’ve run into an issue where I get an error message “Server Was Unable To Process Request,” when trying to create a new customer address record via .NET CRM web services. 

Required Fields And Web Services

When using .NET and CRM web services to create a record, each entity may have certain required fields that need to be set in order to be created, thus maintaining data integrity. For example, Say you were to make the “Name” field required on an Account record in CRM via customizations.  Then on an event of another entity, you wish to use .NET CRM web services to create a new account, you would have to set the “Name” field to some value.

The Trap

The trap here is when you’re developing your code; there are no indicators on which fields are required.  In fact, your program will compile fine.  However, when you go to run your tests, you’ll see an error in the windows event log “Server Was Unable To Process Request…”  This is a very generic CRM error and can be difficult to trace.  If you get this error and you were trying to create a new Customer Address entity, it can be a little bit more complicated.

The Solution

When creating a Customer Address entity via web services, unlike many entities, there’s an extra parameter that needs to get set.  This parameter (in red below), indicates whether the customer address is associated to an Account (objecttypecode = 1), or Contact (objecttypecode = 2).

customeraddress custAddress = new customeraddress(); custAddress.parentid = new Lookup();custAddress.parentid.type = EntityName.account.ToString();custAddress.parentid.Value = accountId; //sets the objecttypecode value to that of the account system entitycustAddress.objecttypecode = new EntityNameReference();

custAddress.objecttypecode.Value = EntityName.account.ToString();

Filed under:
More Posts Next page »