Anything you can do to help would be helpful 

A month or so back, I was having lunch with the SDK documentation team and they asked me “does anyone really use the helpers?” to which, I responded “absolutely”, I then proceeded to agree to writing a blog post on the topic and that is the basis for today’s post.

First off, what are the “helpers” and why do so few people seem to know about them?  They have been in the SDK for quite some time and they are not very hard to use.  I think the problem is that people may not know how to put them to good use on their projects.

I think the first thing to do is to explain what the helpers are and what they can do for you.  The SDK does a pretty good job of explaining what these little guys can do.

“You can add this helper code to your solution to simplify the code that you have to write using QueryExpression.  The helper code also provides static types that can be used for getting and setting attribute values that are not provided in the Web Services Description Language (WSDL).

The helper code can be found in the following folder in the SDK download package: sdk\server\helpers\cs\crmhelpers.

Helper code that contains enumerations, constructors for system types, and classes to help build queries.”

The SDK then goes on to enumerate and describe all of the classes and tools that have been provided… there is a “Readme.doc” file in the helper folder with instructions with how to integrate them in your project. 

So with all this great documentation, why does it seem that so few developers make use of these.  While I have many theories, let’s keep this post to the facts… the facts on how Ascentium has made use of them and the facts about what makes these guys so useful as well as a bit of background and history on the topic.

The root of the problem is that the Web Service Definition Language does not support describing client or consumer side logic, the kind of logic you would use to build constructors, indexers, accessors and methods that could execute on the client prior to serialization and transport of the message.  This means that for CRM types that need to be constructed before they can be set, you have to write code that looks something like this:

asc_entity myEntity = new asc_entity();

myEntity.asc_number = new CrmNumber();

myEntity.asc_number.Value = 12;

WSDL is able to describe what an “asc_entity” and “CrmNumber” are, but it can’t define a constructor on the type CrmNumber that takes in an integer and sets its Value property.

This and many other similar situations is where the “helpers” come.  In CRM 3.0, which was in the .NET 1.x time period, provided a simple set of utility classes to make the code above a little bit easier.  This looked something like this:

asc_entity myEntity = new asc_entity();

myEntity.asc_number = Helper.CreateCrmNumber(12);

Obviously an improvement, especially for more complex types like Lookups.  With the move to CRM 4.0 and the progression to .NET 2.0; partial types provide a much more elegant solution in the CRM 4.0 SDK.  The type helpers now look something like this:

asc_entity myEntity = new asc_entity();

myEntity.asc_number = new CrmNumber(12);

This new approach in CRM 4.0 is much better than previously and the time saving benefits that can be found by using the helpers provided by Microsoft and writing a set of your own can be tremendous… assuming your team knows about them.

The SDK does a pretty good job of discussing all of the helpers available, some of my favorites include:

  • Query Expression Helpers : This is a bunch of helpers that make creating Query Expression objects a lot easier.
  • Type Helpers : Makes creating CRM data types a lot easier.
  • Dynamic Entity Helpers : These add things like indexers, dynamic property helpers and helpful methods like Contains to the WSDL-based Dynamic Entity.

The SDK also provides a “Full Sample” that demonstrates how to use the helpers.  This is located here:

\SDK\Server\FullSample\UsingHelpers

How Ascentium uses the Helpers

To give everyone an idea of how we use these helpers.  We, as a standard have something we call “the standard build tree”, this is a basic clean CRM project that starts out with a vanilla WSDL proxy CS files with the namespace Ascentium.Crm.Common.Sdk.CrmServiceSdk.  These are then checked in our standard tree under \Common\Sdk.  We then also include a copy of the “helpers” (\Common\Extensions), along with our own helpers that exist in the same namespace, using the same partial type method.  Here is an example of an extension we made to the CrmService to make use of the auto-impersonator.

						   1:  \Common\Extensions\CrmService.cs
						   2:   
						   3:  
						using System;
						   4:  
						using System.Collections.Generic;
						   5:  
						using System.Text;
						   6:   
						   7:  
						namespace Ascentium.Crm.Common.Sdk.CrmServiceSdk
						   8:  {
						   9:         public partial class CrmService
						  10:         {
						  11:               public BusinessEntityCollection RetrieveMultiple(QueryBase query, bool useImpersonator)
						  12:               {
						  13:                      if (useImpersonator)
						  14:                      {
						  15:                             using (new Microsoft.Crm.Sdk.CrmImpersonator())
						  16:                             {
						  17:                                   return this.RetrieveMultiple(query);
						  18:                             }
						  19:                      }
						  20:                      else
						  21:                      {
						  22:                             return this.RetrieveMultiple(query);
						  23:                      }
						  24:               }
						  25:         }
						  26:  } 

 

The provided helpers are definitely useful and when integrated into our default build system, they are seamlessly available for use and provide a great deal of benefit at an exceptional low cost.  Since we include a vanilla WSDL in our build tree, we also include a handy script to regenerate these from a VPC.  This allows developers to quickly re-build the WSDL as they make customization and check in their project-specific WSDL proxies.  The code for this is as follows:

 

						   1:  \common\sdk\regenerate_proxies.cmd
						   2:   
						   3:  @echo off
						   4:  cls
						   5:  echo.
						   6:  echo NOTICE: This script generates WSDL Proxies for the DEFAULT ORGANIZATION on the site
						   7:  echo http://localhost:5555 - If this is a multi-organization box, you will need to update this script
						   8:  echo to point to the proper organization
						   9:  echo ================================================================================================
						  10:  echo Also note, this script regenerates all proxies, however under normal circumstances only the
						  11:  echo CrmService Proxy will change.
						  12:  echo.
						  13:  pause
						  14:   
						  15:  echo Generating CrmService SDK for default organization
						  16:  wsdl.exe /out:CrmService.cs /namespace:Ascentium.Crm.Common.Sdk.CrmServiceSdk http://localhost:5555/mscrmservices/2007/crmservice.asmx?wsdl
						  17:   
						  18:  echo Generating Metadata SDK
						  19:  wsdl.exe /out:MetadataService.cs /namespace:Ascentium.Crm.Common.Sdk.MetadataServiceSdk http://localhost:5555/mscrmservices/2007/metadataservice.asmx?wsdl
						  20:   
						  21:  echo Generating CrmDiscoverService SDK
						  22:  wsdl.exe /out:CrmDiscoveryService.cs /namespace:Ascentium.Crm.Common.Sdk.CrmDiscoveryServiceSdk http://localhost:5555/mscrmservices/2007/AD/crmdiscoveryservice.asmx?wsdl

 

Enjoy.

 

Disclaimer:
This posting is provided "AS IS" with no warranties, and confers no rights.

Comments
Hi,

I found this post interesting, as we have made extensive use of the helpers within Crm 3.0, and are looking to do the same within our Crm 4.0 upgrade which will be going live within a month or two.

I have hit one snag however.

The helpers require you to add in a web reference to the Crm Web Service in order to get the partial classes necessary to complete the rest of the code. We want to compile a single dll, which uses the Microsoft.Crm.Sdk.dll and Microsoft.Crm.SdkTypeProxy.dll libraries, and is detached completely from any individual instance (i.e. not requiring a web reference). These helpers would be for use in the plugins registered with individual tenancies on the same physical server, and potentially cross-server.

If we want to do this (which seems like a wise thing to do to me) are we going to have to re-engineer the code to do what we want, or is there a shortcut to acheiving this outcome?

Many thanks,

Antony
The references included in the DLLs you mentioned, already have many of the type and Dynamic Entity helpers built in... this is because they are pre-compiled assemblies that Microsoft was able to extend with features not describable with WSDL. For example, the Dynamic Entity in Microsoft.Crm.Sdk allows you to do stuff like this:

DynamicEntity myDe = new DynamicEntity("account");
myDe.Properties.Add()

Regarding other helpers, you should be able to update the namespaces and types in the shipping helpers to return objects that are compatible with the Proxy DLLs types. I haven't had a chance to try it yet though.
In our usage of CRM, we consider Leads to be Interest and Opportunities to be qualified interest with a larger propensity to purchase. Therefore, a Lead can be an Interest from an Account.

We are trying to tie Leads to accounts (though many leads may not have an account yet) so that any activities that were conducted with the Lead may be reflected in the Account. We've modified the screen so that it displays the customer ID field (which is linked to the account). The lead form works okay now, but if I go into the Account, I cannot see any leads that are attached to that account. Is there something else I can do to get the leads to display under the account? These leads are open leads, not leads that were later converted to accounts.

Any suggestions are helpful!

PS we are still in version 3...
There are several ways of addressing this... I feel I would do this with a simple "hack". I would use ISV.Config to add a new Left Navigation item to the Account form and have it load the Leads Activity "area" page... passing in the "originating lead" ID of the Account on the querystring. This can be done with a little bit of JavaScript in the onload even of the Account form.
Add a New Comment
Name

Email Address

Url

Comment