CrmSvcUtil Option Set Enum Generator Extension

Following from my recent post, I thought I’d release the option set enumeration generator I have been using as well.

I am aware that several existing CrmSvcUtil extensions as well as the unextended CrmSvcUtil generate option set enumerations but this one has several key advantages:

  1. Enumerations are generated as members of the entity classes, not global options sets. This allows copies of global option sets per attribute that uses the global option set.
  2. Duplicate enumeration options are handled by appending the value of the item, not an arbitrary counter. Appending a counter can actually cause bugs that are incredibly difficult to track down if another duplicate instance is added in between two existing duplicates – effectively changing the key/value pair combination without updating dependent code.
  3. Enumerations are generated and consistently named for Option Set, Boolean, State and Status attribute types. Enumerations are referred to in the form “[Entity Schema Name].[Attribute Logical Name]Values” in all cases.

Download the CrmSvcUtil extension at codeplex: CrmSvcUtil Generate Option Set Enums.

To use the extension:

  1. Copy GenerateOptionSetEnums.dll into the directory containing CrmSvcUtil.exe
  2. Run CrmSvcUtil with the following parameters:
CrmSvcUtil.exe ^
/codecustomization:"GenerateOptionSetEnums.CodeCustomizationService, GenerateOptionSetEnums" ^
/codewriterfilter:"GenerateOptionSetEnums.FilteringService, GenerateOptionSetEnums" ^
/url:http://servername/orgname/XRMServices/2011/Organization.svc ^
/out:Enumerations.cs ^

The baseTypes parameter is optional and can be used to override the base types for entity classes which is needed if you have previously generated the wrapper classes with an extension (eg. Microsoft.Xrm.Client.CodeGeneration.CodeCustomization).

To use the generated option set enumerations:

Contact contact = new Contact();
contact.Attributes[Contact.firstnameAttribute] = "Michael";
contact.Attributes[Contact.lastnameAttribute] = "Palmer";
contact.EducationCode = new OptionSetValue((int)Contact.gendercodeValues.Male);
Advertisements

CrmSvcUtil Attribute Constant Generator Extension

A recent question on the CRM MSDN forum made me realise that as far as I can see, no-one has yet created a CrmSvcUtil extension to generate attribute constants. So I did.

Download the CrmSvcUtil extension at codeplex: CrmSvcUtil Generate Attribute Constants.

To use the extension:

  1. Copy GenerateAttributeConstants.dll into the directory containing CrmSvcUtil.exe
  2. Run CrmSvcUtil with the following parameters:
CrmSvcUtil.exe ^
/codecustomization:"GenerateAttributeConstants.CodeCustomizationService, GenerateAttributeConstants" ^
/codewriterfilter:"GenerateAttributeConstants.FilteringService, GenerateAttributeConstants" ^
/url:http://servername/orgname/XRMServices/2011/Organization.svc ^
/out:Attributes.cs

The baseTypes parameter is optional and can be used to override the base types for entity classes which is needed if you have previously generated the wrapper classes with an extension (eg. Microsoft.Xrm.Client.CodeGeneration.CodeCustomization).

To use the generated attribute constants:

Contact contact = new Contact();
contact.Attributes[Contact.firstnameAttribute] = "Michael";
contact.Attributes[Contact.lastnameAttribute] = "Palmer";

CRM 2011 Developer Tools target location for Visual Studio 2010 vs Visual Studio 2012

The path for the targets is different for the Developer Toolkit for Visual Studio 2010 and Visual Studio 2012. This can cause errors when loading the Visual Studio project in the form of the error

The imported project “C:\Program Files (x86)\MSBuild\Microsoft\CRM\Microsoft.CrmDeveloperTools.CrmClient.targets” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

or when attempting to deploy the CrmPackage project from Visual Studio 2010 as the error

Error connecting to CRM Server. [A]Microsoft.CrmDeveloperTools.CrmClient.Entities.Solution cannot be cast to [B]Microsoft.CrmDeveloperTools.CrmClient.Entities.Solution. Type A originates from ‘Microsoft.CrmDeveloperTools.CrmClient, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ in the context ‘LoadFrom’ at location ‘C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Dynamics CRM 2011 Developer Tools\1.0\Microsoft.CrmDeveloperTools.CrmClient.dll’. Type B originates from ‘Microsoft.CrmDeveloperTools, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ in the context ‘LoadFrom’ at location ‘C:\Program Files (x86)\MSBuild\Microsoft\CRM\Microsoft.CrmDeveloperTools.dll’.

or when attempting to deploy the CrmPackage project from Visual Studio 2012 as the error

Error connecting to CRM Server. [A]Microsoft.CrmDeveloperTools.CrmClient.Entities.Solution cannot be cast to [B]Microsoft.CrmDeveloperTools.CrmClient.Entities.Solution. Type A originates from ‘Microsoft.CrmDeveloperTools, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ in the context ‘LoadFrom’ at location ‘C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\Dynamics CRM 2011 Developer Tools\1.0\Microsoft.CrmDeveloperTools.dll’. Type B originates from ‘Microsoft.CrmDeveloperTools.CrmClient, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ in the context ‘LoadFrom’ at location ‘C:\Program Files (x86)\MSBuild\Microsoft\CRM\Microsoft.CrmDeveloperTools.CrmClient.dll’.

depending on the combination of Visual Studio version, installed Developer Toolkit version and previously installed Developer Toolkit versions.

In order to resolve any of these, make sure that the correct targets are referenced in the CrmPackage.csproj file:

  1. In Visual Studio, right click the CrmPackage project and click Unload Project.
  2. Right click on the CrmPackage project and click edit CrmPackage.csproj.
  3. Find the line starting with “<Import Project="$(MSBuildExtensionsPath32)\Microsoft\CRM\" and replace it with the correct path from the list below.
  4. Save and close the file.
  5. Right click on the CrmPackage project and click Reload Project.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\CRM\Microsoft.CrmDeveloperTools.CrmClient.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\CRM\Microsoft.CrmDeveloperTools.12.targets" />

Current key (KeyType : CrmWRPCTokenKey) is expired. This can indicate that a key is not being regenerated correctly.

Current key (KeyType : CrmWRPCTokenKey) is expired. This can indicate that a key is not being regenerated correctly. Current Key : CrmKey(Id:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, ScaleGroupId:00000000-0000-0000-0000-000000000000, KeyType:CrmWRPCTokenKey, Expired:True, ValidOn:01/01/2012 06:49:05, ExpiresOn:01/01/2012 06:49:05, CreatedOn:01/01/2012 06:49:05, CreatedBy:Domain\User.

Every now and then I randomly receive the error above when attempting to access CRM. Usually, restarting both the Microsoft Dynamics CRM Asynchronous Processing Service and Microsoft Dynamics CRM Asynchronous Processing Service (maintenance) resolves this but when it doesn’t, we do the following to resolve the issue:

  1. (Re)start the Microsoft Dynamics CRM Asynchronous Processing Service and Microsoft Dynamics CRM Asynchronous Processing Service (maintenance) services
  2. In a command window, run
    Microsoft.Crm.Tools.WRPCKeyRenewal.exe /R

    in the CRM Tools folder (C:\Program Files\Microsoft Dynamics CRM\Tools\ by default)

CRM2011 RetrieveMultiple SOAP order format

Today I needed to apply an order expression to a SOAP RetrieveMultiple call in JavaScript. I searched high and low online but could only find examples without ordering (<a:Orders />). I used the SOAPLogger tool (see Microsoft Dynamics CRM SOAP Logger) found in the SDK (sdk\samplecode\cs\client\soaplogger) to capture a RetreieveMultiple call with ordering and I thought I’d post an example here to save the next person doing this some time.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <request i:type="a:RetrieveMultipleRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
        <a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
          <a:KeyValuePairOfstringanyType>
            <b:key>Query</b:key>
            <b:value i:type="a:QueryExpression">
              <a:ColumnSet>
                <a:AllColumns>false</a:AllColumns>
                <a:Columns xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
                  <c:string>accountid</c:string>
                  <c:string>name</c:string>
                </a:Columns>
              </a:ColumnSet>
              <a:Criteria />
              <a:Distinct>false</a:Distinct>
              <a:EntityName>account</a:EntityName>
              <a:Orders>
                <a:OrderExpression>
                  <a:AttributeName>name</a:AttributeName>
                  <a:OrderType>Ascending</a:OrderType>
                </a:OrderExpression>
              </a:Orders>
              <a:NoLock>false</a:NoLock>
            </b:value>
          </a:KeyValuePairOfstringanyType>
        </a:Parameters>
        <a:RequestId i:nil="true" />
        <a:RequestName>RetrieveMultiple</a:RequestName>
      </request>
    </Execute>
  </s:Body>
</s:Envelope>

CRM2011 SOAP Money field create/update format

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://schemas.microsoft.com/xrm/2011/Contracts/Services:request. The InnerException message was ‘Error in line 1 position 674. Element ‘http://schemas.datacontract.org/2004/07/System.Collections.Generic:value&#8217; contains data from a type that maps to the name ‘http://www.w3.org/2001/XMLSchema:Money&#8217;. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name ‘Money’ and namespace ‘http://www.w3.org/2001/XMLSchema&#8217;.’. Please see InnerException for more details.

I recently received the error above when attempting to perform a JavaScript CreateRequest on a money field in CRM2011. I found many people experiencing the same issue without any satisfactory resolution.

The following is the correct way to format a Money field in a SOAP create or update request in CRM2011.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">',
  <s:Body>
    <Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <request i:type="a:CreateRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
        <a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
          <a:KeyValuePairOfstringanyType>
            <b:key>Target</b:key>
            <b:value i:type="a:Entity">
              <a:Attributes>
                <a:KeyValuePairOfstringanyType>
                  <b:key>annualincome</b:key>',
                  <b:value i:type="a:Money">
                    <a:Value>1000</a:Value>
                  </b:value>
                </a:KeyValuePairOfstringanyType>
              </a:Attributes>
              <a:EntityState i:nil="true" />
              <a:FormattedValues />
              <a:Id>00000000-0000-0000-0000-000000000000</a:Id>
              <a:LogicalName>Contact</a:LogicalName>
              <a:RelatedEntities />
            </b:value>
          </a:KeyValuePairOfstringanyType>
        </a:Parameters>
        <a:RequestId i:nil="true" />
        <a:RequestName>Create</a:RequestName>
      </request>
    </Execute>
  </s:Body>
</s:Envelope>

CRM2011 Field Data Type Converter

Download: CRM 2011 Field Data Type Converter (1.0.4926.18530)

When trying to import a solution into CRM 2011, if you try import a field with the same name as an existing field but with a different data type, you will receive the following error.

Attribute <Attribute Name> is a <Existing Data Type>, but a <Import Data Type> type was specified.

Usually this happens when attempting to convert a field to a different type. In an environment where there is no data that cannot be lost, this is usually not an issue as one can simply

  1. Delete the existing attribute
  2. Import the solution again

In a production environment or an environment where data cannot be lost, this is not so simple as step 1 above will result in all data in the field being lost.

Enter the CRM2011 Field Data Converter…

The CRM2011 Field Data Converter does the following:

  1. Accepts a CRM Url and credentials, an entity and field, a destination type and various type specific parameters.
  2. Checks whether the supplied entity and field exist and what the field’s existing type is.
  3. Checks whether the source field can be converted to the destination type (see Conversions).
  4. Backs up the existing data.
  5. Deletes the source field.
  6. Creates a new field with the same name and new data type using the supplied type specific parameters.
  7. Populates the data back into the field (converted to the new type – see Conversions).
  8. Outputs a file listing the failures (conversion failures, save failures)

The CRM2011 Field Data Converter DOES NOT do the following:

  • Recover from catastrophic failures: As the data is backed in “in memory”, if a server, network or SQL instance goes down after storing the data and deleting the field, the DATA WILL BE LOST. BACK UP YOUR CRM DATABASE BEFORE RUNNING THIS TOOL.
  • Delete dependencies on the source field: If the source field cannot be deleted manually within CRM, it cannot be deleted by this tool. All dependencies on the field (forms, views, etc) must be manually removed before the tool is run and put back afterwards.

Conversions
  Destination
Boolean DateTime Decimal Double Integer Memo Money String
Source Boolean   * * * * * * *
DateTime   * *
Decimal * *   * * * * *
Double * * *   * * * *
Integer * * * *   * * *
Memo * # * * *   * *
Money * * * * * *   *
String * # * * * * *  
Key
* Convert.To<Type>(sourceValue, CultureInfo.CurrentCulture)
# DateTime.ParseExact(sourceValue, %/datetimepattern%, CultureInfo.CurrentCulture)