Introduction

Introduction Stunnware

The Stunnware Tools for Microsoft Dynamics CRM 4.0 combines a set of tools created for CRM developers and consultants. Initially being divided into multiple standalone applications, the tools framework serves as a single container for all of them, allowing for interaction between components which wasn't possible before.

The current release is available for download on www.stunnware.com and has two different flavors:

  • The Community Edition: It's free and contains the Metadata Viewer, FetchXml Wizard and Excel Export.
  • The Professional Edition: A subscription-based version with access to all tools of the Community Edition plus the Code Generator for C# and VB.NET, the CRM Help File Generator and additional features of the FetchXml wizard..

Content

This help file contains documentation for the following components:

The Stunnware Tools Framework

Describes the base functionality of the framework application. You use it to load extension modules and it manages interaction between these modules. Base functions like the logon to a CRM Server is performed by the framework, while special tasks are done by the extensions.

The Metadata Viewer

Shows the entire metadata of your CRM organization, including entities, attributes, relationships, labels, state and status values, picklist options and more. Integrates with the Excel extension to easily export such data.

The Excel Export

Allows the export of all data displayed in lists.

The FetchXml Wizard

Create FetchXml queries in a visual designer and get to the XML query. Run it to test your settings, convert it into the QueryExpression notation, monitor the SOAP messages being sent and received and more.

The Code Generator

Creates a bunch of wrapper classes working with the Microsoft SDK assemblies. Unless you have a very specific need, you won't have to care about the DynamicEntity object anymore.

The Help File Generator

Document your entire CRM organization by the click of a button. This tool creates a compiled HTML file from the CRM metadata and you can define the design and content yourself.

The Customization Comparer

Compares two CRM customization export files and shows the differences. It's an easy and fast way to know about modifications and helps troubleshooting an installation.

The Trace File Viewer

Analyze CRM Trace Files and find the problems in your CRM system.

The ISV.Config and Sitemap Editor

Provides an XML editor to easily edit the ISV.Config and sitemap without exporting and importing customizations and validates the XML before saving it.


Stunnware Tools Framework - Introduction

Stunnware Tools Framework - Introduction Stunnware

The Stunnware Tools for Microsoft Dynamics CRM 4.0 Framework serves as a container for extension modules, so-called plug-ins, that perform specific tasks. The Framework itself manages these extensions and allows interaction between them. The only notable functionality besides extension management is the logon to a CRM 4.0 organization and the software activation process, which is required to turn the Community Edition into a Professional Edition.

For more information, click one of the links below:

  • Managing Extension Modules

  • Connecting to a CRM 4.0 organization

  • Software Activation

  • Subscription

  • Checking for updates


Managing Extension Modules

Managing Extension Modules Stunnware

The first thing you want to do when starting the Stunnware Tools Framework for the first time, is loading and configuring extensions. Initially, there is nothing loaded into the Framework, so click the Options button on the General page:

The options dialog is displayed, allowing you to load and unload modules. Click on the Management node inside of the Extension Modules category:

The extension list displays all modules found in the application directory and their current states. The State shows one of the following values:

  • System: A system extension that is always loaded. You cannot disable such modules.

  • Loaded: A non-system extension module that was properly loaded.

  • Load Failure: A non-system extension module that failed to load. You hopefully don't ever see this state, but if there is a problem while loading an extension, then it does show this state.

  • Stopped: If an extension reports an error during execution, you are prompted whether you want to stop it. If you select doing so, the status is set to stopped.

  • Inactive: A disabled, non-system extension module.

Note: Some extensions require a valid subscription to be fully functional. When you select an extension, additional messages may be displayed at the bottom of the Extension Manager like in the above screenshot. See Software Activation for more information about how to convert the Community Edition into the Professional Edition.

Enabling and disabling extension modules

To enable a module, simply select it in the list of extension modules and click the Enable button:

Enabling an extension module

To disable an active module, you click the Disable button instead.

Note: As soon as an extension is loaded, you will have new options in the main menu, toolbar, context menus or the options dialog (the same you are currently in).. Which commands are available and how you can access them is specific to each extension. Please read the documentation of the respective modules for further information.

To enable or disable multiple extensions, repeat the step multiple times.


Connecting to a CRM 4.0 organization

Connecting to a CRM 4.0 organization Stunnware

To connect to an organization, click the Connect button om the General ribbon page:

Note: Most menu items and toolbar buttons are disabled until you are connected to a CRM organization.

If you have used Stunnware tools before, you probably have one or more existing profiles on your machine and can simply select an existing connection. If this is the first time you are using a Stunnware tool or you haven't saved a connection profile so far, please enter the information as follows:

Discovery Server: Select the protocol used to connect (either http or https) and then enter the name and port of the CRM server machine running the CRM Discovery Service. If you are connecting to a machine inside your corporate network, then select Internal Network in the dropdown below the Manage button.

Partner Hosted connects to a server hosted by a hosting partner or in your own company when using an IFD setup. Online connects to a CRM Online organization hosted by Microsoft. If you have installed the Outlook Offline client then you can connect to the offline services by clicking the Connect Offline button.

Credentials: When connecting inside the corporate network you usually use your default credentials, which is your current Windows logon plus every credential stored in Windows. However, you can always specify specific credentials by deactivating the Use Default Credentials option and entering the required logon information. This is especially needed when connecting over the Internet. If you check the Save Password option, the password you entered will be stored in the registry and you don't have to enter it again when connecting the next time.

The Organization List shows all CRM organizations you have access to and it also lists the reported URLs to the CRM web application, CRM Service URL and CRM Metadata Service URL. You can use this view to check if the correct URLs are returned from CRM. The organization list is populated whenever you select an item from the Existing Profile list or you click the Retrieve Organizations button.

To connect, select an organization from the organization list and click the OK button, or double-click and organization in the organization list. To cancel the logon process, click on the Cancel button.

Profiles

After successfully connecting to an organization on a CRM Server, you are asked whether or not you want to save the logon information you entered. If you decide to save the data, a profile is created and stored in the registry. The next time you are starting the Stunnware Tools application (or any other Stunnware application), the profile will be available in the Existing Profile list. The data stored in the registry contains the CRM Discovery Service URL, whether you are connecting to a server in the local network or over the Internet and the credentials to use. The password is saved as well when checking the Save Password checkbox.

Note: The data in the registry is not encrypted. However, it's saved to a sub-folder of the HKCU tree and you only can read this data when logged on with this account or having administrative rights to read the data, in which case you are probably an administrator anyway. If you feel that it's not secure, then don't save the password or don't create a profile at all.

Use Manage Profiles to rename or delete profiles:

Profiles are stored in the Windows registry - HKEY_CURRENT_USER\Software\Stunnware\Crm Logon Settings.


Software Activation

Software Activation Stunnware

There are two editions of the Stunnware Tools for Microsoft Dynamics CRM 4.0 Framework: the Community Edition is free and provides great tools like the Metadata Viewer and the FetchXml Wizard. The Professional Edition provides access to all extensions, including these that are not available in the Community Edition.

To activate the Professional Edition, you have to purchase a subscription first. Please see www.stunnware.com for ordering information. Once the order process is completed, you receive an email with your subscription key. To start the activation, click on the Jewel (the blue Stunnware logo):

Then select About Stunnware Tools / Activation.

Copy your subscription key from the email and paste it into the license key text box. Then click the Activate button.

Note: You need administrative rights to activate the software. If you don't have them, the Activate button will be disabled and appropriate warning messages are shown.

Note: The activation process connects to the Internet to validate the entered subscription key. Make sure that you are connected to the Internet and also ensure that your Anti-Virus software is not blocking the application.

After a successful activation, the application closes itself and you have to restart it. This is needed to apply the new settings and start the application in professional mode.

When restarting the application the first time after you have activated it, or after your subscription has been extended, you may receive another warning message that the new subscription information cannot be stored. If you see this message, start the application as an administrator again to finish setup.

Activating on Windows Vista

To activate the application on Windows Vista, you have to run it as an administrator, even if you are logged in with administrative credentials. As Operating Systems are sometimes changing, this process may be required on other systems as well, but at this time it's only known on Vista. To run an application as an administrator, right-click the application icon and select Run As Administrator.

Showing Subscription Information

After you have activated the software, you can always see you subscription information in the activation dialog - the same you used to initially activate the software:

In the sample above, the subscription expires on Augsut 10, 2010. If your subscription expires, the application reverts to the Community Edition.

Your subscription starts when first activating it. If you buy a subscription on October 10, 2009, but activate on October 25, 2009, then the subscription expires on October 25, 2010.

Moving a subscription to another machine

A subscription is bound to a single machine. However, you can always deactivate the license and use it on a different machine. The expiration date won't change though. If your subscription expires on October 25, 2010, and you activate it again on March 17, 2010, then the subscription still expires on October 25, 2010.

Note: A subscription entitles one user to run the Professional Edition on one machine. Using a single subscription to make the application available on a Terminal Server breaks the license agreement and may lead to a deactivation of your subscription. Activating a subscription in a virtual computer and sharing the image to others is illegal as well. Any attempt to bypass the licensing mechanism may lead to a deactivation of your subscription. There is a lot of work involved to maintain this application and it is not for free.

More information about what to expect from a subscription is available in the Subscription topic.


Skins

Skins Stunnware

Skins are a gimmick and allow you to select your favorite look and feel, for instance:

Blue | London Liquid Sky
Office 2007 Black | Pumpkin
Summer 2008 | XMas 2008 Blue

There are many more skins and you last selection will always serve as the default for your next session.


Subscription

Subscription Stunnware

The following is a short Q&A about the Professional Edition Subscription.

How do I order the subscription?

Please refer to our website for the most up-to-date information.

Ordering is done by email. Write to crmsales@stunnware.com and include the following information:

  • Your company name, address and web site. And please write this information in a way that we can understand it.

  • When located inside Europe, please add your VAT number, otherwise we have to charge 19% German sales tax. German customers will always be charged VAT.

  • Your full name and email address. While the email address is contained in your email, you may want to use a different email account. The subscription key will be sent to the email you have specified.

  • The number of subscriptions to purchase.

The subscription may also be available from our partners. Please visit our reseller list for more information.

How do I get my subscription key?

Subscription keys are sent to the email address you specified when ordering after we have received your full payment.

What payment options do you have?

We accept bank transfers (preferred in the EU), checks and credit card payments through our PayPal account. You do not need a PayPal account to use it. However, if you do have a PayPal account, then you can use it as well. Please let us know if you want to pay by credit card and we create a payment request. You will receive an email from PayPal guiding you through the payment process.

How long does the subscription last?

The subscription lasts for 12 months after your first activation. If you purchase on 10/1/2008 but activate the software on 10/15/2008, then it will be valid to 10/15/2009.

What happens after the subscription ends?

When your subscription expires, the Stunnware Tools application reverts to the Community Edition. The features of the Professional Edition won't be available afterwards.

How do I renew a subscription?

Follow the same steps as when ordering the subscription but add your unique subscription key. Your subscription will be extended for another 12 months and the Stunnware Tools application will update itself and tell you about the extended subscription.

How do I receive software updates?

The latest version is always available on our website. There is no separate download for the Professional Edition. The easiest way to get notified about new versions is subscribing to Michael Höhne's CRM blog.

Don't you think that it's too much money for a one-year subscription?

No, I don't think so. Just imagine how much time the tool saves in 12 months and multiply with your hourly rate. If it's not more than what you are paying for the subscription, then you definitely don't need it.

Can I evaluate the software?

There is no evaluation license available. However, the Code Generator and the CRM Documentation extensions do work in the Community Edition, but are limited to the Account and Contact entity, so you can try it out instantly. If this is all you need, then you are a lucky guy. The extended features of the FetchXml wizard are not available in the Community Edition though.

How often will the software be updated?

This is hard to tell. It depends on your feedback which features will be included. Feedback can be sent at any time to michael.hoehne@stunnware.com and we appreciate any kind of comment.

Is the software bug-free?

Probably not. The entire application consists of > 100.000 lines of code and it's almost impossible to not include any error in such a project. However, we are using the tool ourselves and fix any problem we encounter. If you have a problem, please send an email to michael.hoehne@stunnware.com and describe the problem as detailed as possible.

Can I use the subscription on another machine?

Yes you can. However, you have to deactivate the subscription first. A subscription allows using the software on one machine, but it is not tied to a specific system. See Software Activation for details.


Checking for updates

Checking for updates Stunnware

Since version 4.5.27 an automatic version check is included in the application. When a new version is available, then you are notified by the application. No automatic update is performed though. You can turn this feature off and use a manual check though. To do so, click on the Jewel (the blue Stunnware logo):

Then select Check for Updates. The application tells you whether or not a newer version of the Stunnware Tools is available for download on the Stunnware web.


CRM Metadata Viewer - Introduction

CRM Metadata Viewer - Introduction Stunnware

The general purpose of the Metadata Viewer is to get a quick overview of entities, attributes, relationships and everything else contained in the CRM Metadata. CRM does provide a graphical representation of the metadata. Type in http://crmserver:port/organization/sdk/list.aspx in Internet Explorer, replacing crmserver, port and organization with the respective values, and you get an entity list and information about attributes and relationships as well. However, when extensively working with information from the CRM Metadata, you may find the Metadata Viewer easier to use.

Note: Stunnware has made available Metadata Viewers since early 2006 and previous releases can still be found on Michael Höhne's CRM Blog. It is a free extension and doesn't require a subscription to be used.

For more information, click one of the links below:

  • Enabling Extension Modules

  • Entity List

  • Entity Details

  • Attribute List

  • Attribute Details

  • Relationship List

  • Relationship Details

  • States and Statuses

  • Privileges

  • Labels


CRM Metadata Viewer - Entity List

CRM Metadata Viewer - Entity List Stunnware

To show a list of all entities in the current organization, you either click the Entity List toolbar button or Entity List from the Metadata page:

The following columns are displayed for each entity.

  • Name: The logical name
  • Display Name: The display name
  • Collection Name: The display collection name
  • Type Code: The entity type code, aka object type code
  • Ownership: The ownership type
  • Custom: shows yes, if a custom entity
  • Customizable: shows yes, if customizable
  • Report View Name: the name of the filtered view used for reporting
  • Primary Field: name of the primary field
  • Primary Key: name of the primary key
  • Edit URL: the URL used to create and edit records in the CRM web. This information is not obtained from the metadata and may be incorrect. Use with care!
  • Description: The entity description.

To drill down into an entity double-click the entity row or click the Show Entity Details button in the ribbon. Additional functions may be available in the context menu, which is accessed by right-clicking an entity row:

Entity List Context Menu

Whether or not a context menu is displayed depends on the enabled extension modules. Some functions may also be unavailable in the Community Edition.


CRM Metadata Viewer - Entity Details

CRM Metadata Viewer - Entity Details Stunnware

The Entity Details window contains almost every data you can get from an entity:

For more information about the data displayed in the tabs please refer to the following links:

  • Attributes

  • Relationships

  • States & Statuses

  • Privileges

  • Labels

  • Properties


CRM Metadata Viewer - Attribute List

CRM Metadata Viewer - Attribute List Stunnware

The attribute list displays all attributes of an entity and shows a variety of common properties:

The list displays the following information:

  • Name: The attribute's logical name
  • Type: The attribute type
  • Attribute Of: If set, the attribute is a virtual property of another attribute. For instance, the accountcategorycodename refers to the name property of the accountcategorycode attribute.
  • Default Value: The attribute's default value
  • Display Name: The display name
  • Display Mask: The display mask is a combination of flags, defining where an attribute can be used
  • Custom: Shows yes for custom attributes
  • Required Level: Shows whether an attribute is required, recommended or optional
  • Read: Shows yes, if the attribute is valid for read
  • Create: Shows yes, if the attribute is valid for create
  • Update: Shows yes, if the attribute is valid for update
  • Additional Settings: Specific settings not common to all attributes
  • Description: The attribute description

To drill down into an attribute, double-click the entity row or click the Show Attribute Details button in the ribbon. Additional functions may be available in the context menu, which is accessed by right-clicking an entity row.


CRM Metadata Viewer - Attribute Details

CRM Metadata Viewer - Attribute Details Stunnware

The Attribute Details window contains the entire description of an attribute:

The Properties tab shows single-valued properties of the selected attribute. Besides the standard attribute properties, the property grid also includes a lot of extended information, like IsRequiredForCreate and IsRequiredForCrmFormCreate. These values are based on my CRM 3.0 metadata experience and may not be totally correct. If you want to know about how I'm calculating them, see Advanced Metadata Scenarios.

The Options tab displays values of picklist, state and status fields:

For more information about the Labels tab please refer to the following link:

  • Labels


CRM Metadata Viewer - Relationship List

CRM Metadata Viewer - Relationship List Stunnware

The relationship list displays all relationships of an entity and shows a variety of common properties:

The list displays the following information:

  • Schema Name: The relationship's logical name
  • Type: The relationship type (1:many, many:1, many:many)
  • Custom: Shows yes for custom relationships
  • Referenced Entity, Referenced Attribute, Referencing Entity, Referencing Attribute: The end-points of the relationship

To drill down into a relationship either double-click a relationship row or click the Show Relationship Details button in the ribbon. Additional functions may be available in the context menu, which is accessed by right-clicking a relationship row.


CRM Metadata Viewer - Relationship Details

CRM Metadata Viewer - Relationship Details Stunnware

The Relationship Details window contains the entire description of a relationship:

For more information on labels, please refer to the Labels topic.


CRM Metadata Viewer - States and Statuses

CRM Metadata Viewer - States and Statuses Stunnware

The States and Statuses tab display the available states and statuses in two different ways: as a tree, which is easy to understand which statuses belong to a state, and in two lists, one showing the states and the other showing the statuses:

States and Statuses


CRM Metadata Viewer - Privileges

CRM Metadata Viewer - Privileges Stunnware

The Privileges tab display the defined privileges of en entity. Note that not all entities define a privilege set:


CRM Metadata Viewer - Labels

CRM Metadata Viewer - Labels Stunnware

The Labels tab is used in various locations and displays labels in all languages enabled for the current organization:


CRM Metadata Viewer - Properties

CRM Metadata Viewer - Properties Stunnware

The Properties tab displays various properties of an entity that do not fall into other categories. Each row displays the name and value of a single property. When clicking a row, a description of the property is displayed at the bottom.


Excel Export - Introduction

Excel Export - Introduction Stunnware

The Excel Export is a small utility allowing to export data from views and is only visible in context menus of list views:

Whatever is displayed in the list will be exported to an XML file using the Excel 2003 XML format:

That's all the extension does and there is nothing for you to configure. It's just there to copy, print or further work with the displayed data.

For more information, click one of the links below:

  • Enabling Extension Modules


CRM Code Generator - Introduction

CRM Code Generator - Introduction Stunnware

A big disadvantage when working with the Microsoft CRM SDK assemblies, is that you have to use dynamic entities most of the time. While the DynamicEntity class was enhanced in CRM 4.0 to make it easier to use, you're losing a lot of benefits you had when using the web services:

  • Type and property checking: You don't know at compile time if your code is correct, because you are not using strongly typed classes and you don't access named properties.

  • Intellisense: because of the above, you also don't get any context-sensitive help while developing in Visual Studio

  • You have to use the more complex RetrieveRequest and RetrieveMultipleRequest messages with the Execute method instead of the Retrieve and RetrieveMultiple methods.

All in all your code becomes more complex and it takes more time to develop and test. The Code Generator module gives you back everything you lost plus some additional benefits:

  • Works with the CrmService class and the ICrmService interface from the Microsoft CRM SDK assemblies

  • Creates C# and VB.NET code

  • Creates classes for all or selected entities, providing nullable properties for easy access

  • All attribute names in each class are defined as constant strings, so you never have to look at CRM again to remember the correct spelling

  • Creates enumerations for all picklists, state and status attributes

  • Adds methods for easy use of the CRUD operations (Create, Retrieve, RetrieveMultiple, Update, Delete)

  • Adds methods to change an entity's state

  • Provides easy management of all reference types (Lookup, Owner, Customer), e.g. you write account.Primarycontactid = myContact.ToReference()

  • Adds comments to classes, properties and methods, which are available in Visual Studio through Intellisense.

  • Allows you to create your own code generation templates. If you want some special methods in every class, then simply add it to the template files.

Note: The Code Generator module requires the Professional Edition to be fully functional. It's limited to accounts and contacts in the Community Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules

  • Creating and editing Code Generator Projects

  • Code Generation


CRM Code Generator - Creating and editing Projects

CRM Code Generator - Creating and editing Projects Stunnware

To create a new project, select the Code Generator page and click the New button:

A Save As dialog appears, prompting for the location of the new project file:

Save New Project

Select the folder and specify the file name. The default extension used is SWCGP, which is short for Stunnware Code Generator Project. Click the Save button and you are presented with the project settings window:

You can create wrapper classes for C# and/or VB.NET. To create C# files, you have to specify the Template Folder and the Output Folder in the C# group. To create VB.NET files, specify the same settings in the VB.NET group. If you enter information in both groups, then code for C# and VB.NET is created.

Templates

A template folder always has three files:

  • File.cs or File.vb: A general template for all files being created in the code generation process. You should not change this file.

  • BaseClass.cs or BaseClass.vb: All wrapper classes derive from an abstract base class. This base class is defined in the BaseClass file. Properties and methods you define in the base class are available in all wrapper classes, unless you mark them as private.

  • Class.cs or Class.vb: This template is used to create a single wrapper class.

After installing the Stunnware Tools application, you find a C# and a VB.NET template in <Program Files>\Stunnware\Stunnware Tools for Microsoft Dynamics CRM 4.0\Templates\Code Generator. You can use these template folders in your project settings or point to an alternate location. It is recommended to copy the default templates to an alternate location if you plan to change them.

For a quick start, simply select the template folders in the installation folder:

Default Code Templates

Output Folders

The output folders specify where to create the output files. It can be any location on your system or a network folder. All being required is that you have appropriate rights to create files. For a quick start, simply create two new folders and select them in the project settings:

Note: You can select any output folder and a common scenario is writing the output files to a subfolder of a Visual Studio project directory. After the files have been generated, you add them to the Visual Studio project and can instantly use them. Whenever you modify the CRM entities, all you need to do is re-generating the files and your Visual Studio solution is up-to-date.

Namespaces

The Target Namespace is used as the namespace in all generated classes. If you use the default value of Stunnware.Crm4.WebServiceClasses, then the all created files will use this namespace:

C#

namespace Stunnware.Crm4.WebServiceClasses {
}

VB.NET

Namespace Stunnware.Crm4.WebServiceClasses
End Namespace

Options

All generated classes are named <Class Prefix><Entity Name>. When using the default Class Prefix of SwCrm and creating a wrapper class for the account entity, then the resulting name is SwCrmaccount. If you do not specify a class prefix, then the resulting class name matches the entity name. As SwCrmaccount doesn't look good, you can activate the Capitalize class and property names option. It changes the first name of an entity or attribute name to uppercase and also replaces underscores. For instance, a custom attribute named sw_blogurl will become a property named SwBlogurl and the account's class name will be SwCrmAccount.

The easiest way to find out what these options do is generating the code. However, here's a quick reference with some sample settings:

CRM Entity/Attribute | Class Prefix | Capitalize | Resulting class/property name
account | Crm | no | Crmaccount
account | Crm | yes | CrmAccount
account |  | no | account
account |  | yes | Account
sw_project | Crm | no | Crmsw_project
sw_project | Crm | yes | CrmSwProject
sw_project |  | no | sw_project
sw_project |  | yes | SwProject

Include Custom Entities and Include Custom Attributes are checked by default. When unchecked, only system entities or system attributes are generated. You can define the entities more granularly on the Entities tab though. The following table shows what is generated, based on the settings of these two flags:

Include Custom Entities | Include Custom Attributes | Result
yes | yes | All entities and attributes are generated.
yes | no | All entities are generated, but custom attributes are not included, except the primary key and primary field of custom entities.
no | yes | Only system entities are generated, but all custom attributes are contained.
no | no | Only system entities and system attributes are generated. All customizations are ignored.

The Create single file for all classes option defines whether to create one file containing all classes (like the reference.cs or reference.vb you know from an WSDL import) or one file for each entity. As the generated files should not be modified, a single file usually is easier to use, because you only have to include one file into to your Visual Studio project instead of multiple.

Exclude entities without a primary field is checked by default and suppresses the generation of classes that do not define a primary field. The primary field usually is "name" and is used in views and lookup fields. However, you can generate wrapper classes for all entities when un-checking this option. There may be errors in code generation though, so be careful when using this option.

Note: Do not modify the generated classes if you want to add code to them. The default templates generate partial classes, allowing you to add new code files to your Visual Studio project containing partial classes as well. The compiler will merge these files and you can re-generate the wrapper classes without overwriting your changes.

Entity Selection

The Entities tab contains the set of entities that can be generated. When activating the Create classes for all entities, the code generator creates a wrapper class for all entities. While this is easy to use, you usually don't need all entities in your project and selecting the required classes in the list makes more sense:

Note: There's no risk in selecting the entities in the list. When your project grows and you need support for more entities, you simply select the new entities and run the code generation again. The benefit is smaller code and faster compilation.

Next: Code Generation


CRM Code Generator - Generating Code

CRM Code Generator - Generating Code Stunnware

After you have setup your project, you can start the code generation at any time. Click the Build button and wait until the code generation process finishes:

The code is usually generated in a few seconds and most of the time is needed to read the CRM Metadata.

While clicking the button is easy, you of course have to specify what needs to be generated. The default templates provide a rich set of features, but sooner or later you want to add your own code to the generation process and need to understand your options. Please refer to the following list for more information:

  • The File template

  • The BaseClass template

  • The Class template

  • Placeholders


CRM Code Generator - File Template

CRM Code Generator - File Template Stunnware

The file template is a simple file containing a snippet used in all generated files. You should not change this file to prevent program failures. The file template contains the following code:

C#

namespace _TARGETNAMESPACE_ {
 //_CLASSES_
}

VB.NET

Namespace _TARGETNAMESPACE_
 '_CLASSES_
End Namespace

The _CLASSES_ comment is replaced with one or all generated classes, based on the Create single file for all classes option in the project settings.

The _TARGETNAMESPACE_ is replaced with the value you specified in the Target Namespace text box in the project settings. If you use the default value of Stunnware.Crm4.WebServiceClasses, then the all created files will use this namespace:

C#

namespace Stunnware.Crm4.WebServiceClasses {
}

VB.NET

Namespace Stunnware.Crm4.WebServiceClasses
End Namespace

For a list of placeholders refer to the Placeholders topic.


CRM Code Generator - BaseClass Template

CRM Code Generator - BaseClass Template Stunnware

All wrapper classes derive from an abstract base class being defined in the BaseClass template file. Depending on the .NET language, the file extension is cs (C#) or vb (VB.NET). All properties and methods you define in the base class are available in the wrapper classes, unless you mark them as private.

The default templates define the following properties and methods:

  • Activate and Deactivate: Activates or deactivates an entity. Note that this only works if the appropriate states are defined in the entity. Most entities to define the Active and Inactive states, but not all of them. The availability of the Activate and Deactivate methods doesn't mean that they will succeed.
  • Create: Creates a new record in Microsoft CRM.
  • Delete: Deletes a record in Microsoft CRM.
  • GetProperties: Returns a PropertyCollection containing all properties of the current instance. This collection can be assigned to the Property property of a DynamicEntity instance.
  • Merge: Merges the properties of a DynamicEntity object into an existing entity.
  • ToDynamicEntity: Converts an object to a DynamicEntity instance.
  • ToReference: Returns an entity reference object pointing to the object. This entity reference can be assigned to lookup, owner and customer fields.
  • Update: Updates the current record in Microsoft CRM.

There are a variety of helper methods used to set property values. These are named Get<TypeName> and Set<TypeName>, e.g. GetBoolean, GetState or SetMoney. Do not remove these helper methods, otherwise the generated classes will be non-functional.

You will also note code fragments for each data type. As an example, for each integer property the following code fragment is inserted when generating C# code:

//_INTEGER_PROPERTY_START
///
<summary>
/// _ATTRIBUTEDESCRIPTION_
///
</summary>
public
int? _INTEGER_PROPERTY {
get {
return
this.GetInteger("_ATTRIBUTENAME_");
}
set {
this.SetInteger("_ATTRIBUTENAME_",
value); }
}
//_INTEGER_PROPERTY_END

The comments //_INTEGER_PROPERTY_START and //INTEGER_PROPERTY_END are not included in the generated classes. All other placeholders (_ATTRIBUTEDESRIPTION_, ATTRIBUTENAME_, INTEGER_PROPERTY) are replaced with the corresponding attribute values. A typical result in the generated classes is this:

/// <summary>
/// Number of employees at the account.
/// </summary>
public int? Numberofemployees {
 get { return this.GetInteger("numberofemployees"); }
set { this.SetInteger("numberofemployees", value); }
}

The base class also defines two constructors that are overridden in all entity classes: a constructor without any parameter and a constructor taking a DynamicEntity.

Why a base class?

When working with CRM data you often want to write generic methods. The object model doesn't allow this though, because CRM's BusinessEntity class doesn't provide any usable method or property. The base class used in the code generator, however, does provide such code. For instance, it contains the following declaration:

C#

public abstract string EntityTypeName { get; }
public abstract System.Guid? Id { get; set; }

VB

Public MustOverride ReadOnly Property EntityTypeName() As String
Public MustOverride Property Id() As Nullable(Of System.Guid)

These properties are marked abstract and the final implementation is defined in the generated entity classes. However, you can have an array of instances of this base class and know about their entity type name and primary key, which usually is all you need to perform bulk actions.

For a list of placeholders refer to the Placeholders topic.


CRM Code Generator - Class Template

CRM Code Generator - Class Template Stunnware

For each entity you have selected in the project settings, a wrapper class is generated. This class inherits from the base class and only implements the specific entity attributes and methods. You can add code to the class template and it will be generated for each entity. You will need to use placeholders in order to make it generic though.

The default templates define the following properties and methods:

  • Constructors: A parameter-less constructor and a constructor taking a DynamicEntity object. Both constructors call the implementation of the base class.
  • Properties: Properties for all attributes. In difference to the CRM object model, you are not dealing with CRM types. For instance, instead of using a CrmBoolean, you get a nullable boolean property.
  • Attributes class: A utility class containing the entity's attribute names.
  • State and Status enumerations: Enumerations for all state and status values.
  • Picklist enumerations: An enumeration for every picklist, containing the available picklist options.
  • Retrieve: Retrieves a single record and returns it as one of the generated classes, instead of a DynamicEntity.
  • RetrieveMultiple: Executes a query and returns an item list, where each item is one of the generated classes, instead of a DynamicEntity.
  • SetState: Implements a method to set the entity state using the generated state and status enumerations.

The class template uses definitions made in the base class and uses a variety of placeholders. Please refer to these topics to full understand the code generation process, before making changes.


CRM Code Generator - Placeholders

CRM Code Generator - Placeholders Stunnware

Placeholders are used to dynamically create content in the generated base class and entity classes. The template files itself are valid .NET code and can be added to a .NET solution and it is strongly recommended to do so if you want to make changes to them. It gives you the power of Visual Studio .NET and ensures that your code is syntactically correct. Some placeholders defined in the base class were added to have valid .NET code only and they are removed from the generated files. See the _REMOVE_ placeholder for samples.

The following table shows the available placeholders and their meaning. For detailed information click on on placeholder's name.

_ATTRIBUTEDESCRIPTION_ | The _ATTRIBUTEDESCRIPTION_ is replaced with the description of an attribute.
_ATTRIBUTENAME_ | _ATTRIBUTENAME_ is replaced with an attribute's logical name.
_CLASSNAME_ | The _CLASSNAME_ refers to the full class name of an entity. It uses the project settings to capitalize and prefix the name correctly.
_CLASSES_ | _CLASSES_ is either replaced with a single class, representing one entity, or with all entities you have selected in the project settings. You should not move or remove this placeholder.
_CLASSPREFIX_ | The _CLASSPREFIX_ refers to the class prefix specified in the project settings. It may be an empty string or any valid identifier you like.
_CREATE_DUPLICATE_IMPLEMENTATION_ | _CREATE_DUPLICATE_IMPLEMENTATION_ is replaced with an implementation creating a copy of an existing object. It's not a clone implementation, because read-only fields are not included.
_ENTITYDESCRIPTION_ | The _ENTITYDESCRIPTION_ is replaced with the description of an entity.
_FIELDNAMES_ | _FIELDNAMES_ is replaced with a list of constant string expressions, each identifying a single attribute.
_LOGICALNAME_ | _LOGICALNAME_ is replaced with the logical name of an entity, e.g. account or contact. This is also known as the entity type name.
_PICKLIST_OPTIONS_ | _PICKLIST_OPTIONS_ is replaced with an enumeration of available picklist options.
_PRIMARYFIELDPROPERTY_ | The _PRIMARYFIELDPROPERTY_ is replaced with the name of an entity's primary field.
_PRIMARYKEYPROPERTY_ | The _PRIMARYKEYPROPERTY_ is replaced with the name of an entity's primary key.
_PROPERTIES_ | _PROPERTIES_ is replaced with appropriate code for all entity attributes. Each attribute corresponds to one property in the code. You should not move or remove this placeholder.
_REFERENCEDTYPE_ | _REFERENCEDTYPE_ is used in lookup properties. The code generator knows from the metadata, which entity is referenced in a lookup field and sets the entity type name accordingly.
_REMOVE_ | Any line ending with _REMOVE_ is removed from the generated code.
_REMOVE_IN_BASE_CLASS_START_ & _REMOVE_IN_BASE_CLASS_END_ | Everything between _REMOVE_IN_BASE_CLASS_START_ and _REMOVE_IN_BASE_CLASS_END_, including the comments itself, is removed from the base class after code generation has finished. The code serves as a template only and is not needed in the final output.
_STATE_ENUM_ | _STATE_ENUM_ is replaced with an enumeration of the available entity states.
_STATUS_ENUM_ | _STATUS_ENUM_ is replaced with an enumeration of the available entity statuses.
_TARGETNAMESPACE_ | The _TARGETNAMESPACE_ refers to the target namespace you have specified in the project settings.


CRM Code Generator - _ATTRIBUTEDESCRIPTION_ Placeholder

CRM Code Generator - _ATTRIBUTEDESCRIPTION_ Placeholder Stunnware

The _ATTRIBUTEDESCRIPTION_ is replaced with the description of an attribute.

C#
Sample definition

//_BOOLEAN_PROPERTY_START
/// <summary>
/// _ATTRIBUTEDESCRIPTION_
/// </summary>
public bool? _BOOLEAN_PROPERTY {
get { return this.GetBoolean("_ATTRIBUTENAME_"); }
set { this.SetBoolean("_ATTRIBUTENAME_", value); }
}
//_BOOLEAN_PROPERTY_END

Sample output

/// <summary>
/// Information about whether to allow sending direct e-mail to the account.
/// </summary>
public bool? Donotbulkemail {
get { return this.GetBoolean("donotbulkemail"); }
set { this.SetBoolean("donotbulkemail", value); }
}
VB.NET
Sample definition

'_BOOLEAN_PROPERTY_START
''' <summary>
''' _ATTRIBUTEDESCRIPTION_
''' </summary>
Public Property _BOOLEAN_PROPERTY() As Nullable(Of Boolean)
Get
Return Me.GetBoolean("_ATTRIBUTENAME_")
End Get
Set(ByVal value As Nullable(Of Boolean))
Me.SetBoolean("_ATTRIBUTENAME_", value)
End Set
End Property
'_BOOLEAN_PROPERTY_END

Sample output

''' <summary>
''' Information about whether to allow sending direct e-mail to the account.
''' </summary>
Public Property Donotbulkemail() As Nullable(Of Boolean)
Get
Return Me.GetBoolean("donotbulkemail")
End Get
Set(ByVal value As Nullable(Of Boolean))
Me.SetBoolean("donotbulkemail", value)
End Set
End Property


CRM Code Generator - _ATTRIBUTENAME_ Placeholder

CRM Code Generator - _ATTRIBUTENAME_ Placeholder Stunnware

_ATTRIBUTENAME_ is replaced with an attribute's logical name.

C#
Sample definition

//_BOOLEAN_PROPERTY_START
/// <summary>
/// _ATTRIBUTEDESCRIPTION_
/// </summary>
public bool? _BOOLEAN_PROPERTY {
get { return this.GetBoolean("_ATTRIBUTENAME_"); }
set { this.SetBoolean("_ATTRIBUTENAME_", value); }
}
//_BOOLEAN_PROPERTY_END

Sample output

/// <summary>
/// Information about whether to allow sending direct e-mail to the account.
/// </summary>
public bool? Donotbulkemail {
get { return this.GetBoolean("donotbulkemail"); }
set { this.SetBoolean("donotbulkemail", value); }
}
VB.NET
Sample definition

'_BOOLEAN_PROPERTY_START
''' <summary>
''' _ATTRIBUTEDESCRIPTION_
''' </summary>
Public Property _BOOLEAN_PROPERTY() As Nullable(Of Boolean)
Get
Return Me.GetBoolean("_ATTRIBUTENAME_")
End Get
Set(ByVal value As Nullable(Of Boolean))
Me.SetBoolean("_ATTRIBUTENAME_", value)
End Set
End Property
'_BOOLEAN_PROPERTY_END

Sample output

''' <summary>
''' Information about whether to allow sending direct e-mail to the account.
''' </summary>
Public Property Donotbulkemail() As Nullable(Of Boolean)
Get
Return Me.GetBoolean("donotbulkemail")
End Get
Set(ByVal value As Nullable(Of Boolean))
Me.SetBoolean("donotbulkemail", value)
End Set
End Property


CRM Code Generator - _CLASSES_ Placeholder

CRM Code Generator - _CLASSES_ Placeholder Stunnware

_CLASSES_ is either replaced with a single class, representing one entity, or with all entities you have selected in the project settings. You should not move or remove this placeholder.


CRM Code Generator - _CLASSNAME_ Placeholder

CRM Code Generator - _CLASSNAME_ Placeholder Stunnware

The _CLASSNAME_ refers to the full class name of an entity. It uses the project settings to capitalize and prefix the name correctly.

C#
Sample definition

public partial class _CLASSNAME_ : _TARGETNAMESPACE_._CLASSPREFIX_Entity {
}
Sample output

public partial class SwCrmAccount : Stunnware.Crm4.WebServiceClasses.SwCrmEntity {
}
VB.NET
Sample definition

Partial Public Class CLASSNAME_
Inherits _TARGETNAMESPACE_._CLASSPREFIX_Entity
End Class
Sample output

Partial Public Class SwCrmAccount
Inherits Stunnware.Crm4.WebServiceClasses.SwCrmEntity
End Class


CRM Code Generator - _CLASSPREFIX_ Placeholder

CRM Code Generator - _CLASSPREFIX_ Placeholder Stunnware

The _CLASSPREFIX_ refers to the class prefix specified in the project settings. It may be an empty string or any valid identifier you like.

C#
Sample definition

public abstract partial class _CLASSPREFIX_Entity {
}
Sample output

public abstract partial class SwCrmEntity {
}
VB.NET
Sample definition

Partial Public MustInherit Class _CLASSPREFIX_Entity
Sample output

Partial Public MustInherit Class SwCrmEntity


CRM Code Generator - _CREATE_DUPLICATE_IMPLEMENTATION_ Placeholder

CRM Code Generator - _CREATE_DUPLICATE_IMPLEMENTATION_ Placeholder Stunnware

_CREATE_DUPLICATE_IMPLEMENTATION_ is replaced with an implementation creating a copy of an existing object. It's not a clone implementation, because read-only fields are not included.

Note: It is important to enter a space between the comment operator and the term _CREATE_DUPLICATE_IMPLEMENTATION_.

C#
Sample definition

/// <summary>
/// Creates a copy of the current object, excluding properties that are not valid for creation.
/// </summary>
/// <returns></returns>
public _CLASSNAME_ CreateDuplicate() {
// _CREATE_DUPLICATE_IMPLEMENTATION_
return null; // _REMOVE_
}

Sample output

/// <summary>
/// Creates a copy of the current object, excluding properties that are not valid for creation.
/// </summary>
/// <returns></returns>
public SwCrmAccount CreateDuplicate() {
SwCrmAccount c = new SwCrmAccount();
c.Defaultpricelevelid = this.Defaultpricelevelid;
c.Address1Shippingmethodcode = this.Address1Shippingmethodcode;
c.Industrycode = this.Industrycode;
...
}
VB.NET
Sample definition

''' <summary>
''' Creates a copy of the current object, excluding properties that are not valid for creation.
''' </summary>
''' <returns></returns>
Public Function CreateDuplicate() As _CLASSNAME_
' _CREATE_DUPLICATE_IMPLEMENTATION_
Return Nothing ' _REMOVE_
End Function
Sample output

''' <summary>
''' Creates a copy of the current object, excluding properties that are not valid for creation.
''' </summary>
''' <returns></returns>
Public Function CreateDuplicate() As SwCrmAccount
Dim c As New SwCrmAccount()
c.Defaultpricelevelid = Me.Defaultpricelevelid
c.Address1Shippingmethodcode = Me.Address1Shippingmethodcode
c.Industrycode = Me.Industrycode
...
End Class


CRM Code Generator - _ENTITYDESCRIPTION_ Placeholder

CRM Code Generator - _ENTITYDESCRIPTION_ Placeholder Stunnware

The _ENTITYDESCRIPTION_ is replaced with the description of an entity.

C#
Sample definition

/// <summary>
/// _ENTITYDESCRIPTION_
/// </summary>
public partial class _CLASSNAME_ : _TARGETNAMESPACE_._CLASSPREFIX_Entity {
}
Sample output

/// <summary>
/// Business that represents a customer or potential customer. The company that is billed in business transactions.
/// </summary>
public partial class SwCrmAccount : Stunnware.Crm4.WebServiceClasses.SwCrmEntity {
}
VB.NET
Sample definition

''' <summary>
''' _ENTITYDESCRIPTION_
''' </summary>
Partial Public Class _CLASSNAME_
 Inherits _TARGETNAMESPACE_._CLASSPREFIX_Entity
End Class
Sample output

''' <summary>
''' Business that represents a customer or potential customer. The company that is billed in business transactions.
''' </summary>
Partial Public Class SwCrmAccount
 Inherits Stunnware.Crm4.WebServiceClasses.SwCrmEntity
End Class


CRM Code Generator - _FIELDNAMES_ Placeholder

CRM Code Generator - _FIELDNAMES_ Placeholder Stunnware

_FIELDNAMES_ is replaced with a list of constant string expressions, each identifying a single attribute.

Note: It is important to enter a space between the comment operator and the term _FIELDNAMES_.

C#
Sample definition

public static class Attributes {
 // _FIELDNAMES_
}

Sample output

public static class Attributes {
public const string Defaultpricelevelid = "defaultpricelevelid";
public const string Address1Shippingmethodcode = "address1_shippingmethodcode";
public const string Industrycode = "industrycode";
public const string Address2Fax = "address2_fax";
...
}
VB.NET
Sample definition

Public Class Attributes
 Private Sub New()
End Sub

' _FIELDNAMES_
End Class

Sample output

Public Class Attributes
 Private Sub New()
 End Sub

Public Const Defaultpricelevelid As String = "defaultpricelevelid"
Public Const Address1Shippingmethodcode As String = "address1_shippingmethodcode";
Public Const Industrycode As String = "industrycode";
Public Const Address2Fax As String = "address2_fax";
...
End Class


CRM Code Generator - _LOGICALNAME_ Placeholder

CRM Code Generator - _LOGICALNAME_ Placeholder Stunnware

_LOGICALNAME_ is replaced with the logical name of an entity, e.g. account or contact. This is also known as the entity type name.

C#
Sample definition

/// <summary>
/// Returns the entity's display name (_PRIMARYFIELDPROPERTY_)
/// </summary>
public override string ToString() {
return (this._PRIMARYFIELDPROPERTY_ == null) ? null : this._PRIMARYFIELDPROPERTY_.ToString();
}

Sample output

/// <summary>
/// Returns the entity's display name (Name)
/// </summary>
public override string ToString() {
 return (this.Name == null) ? null : this.Name.ToString();
}
VB.NET
Sample definition

''' <summary>
''' Returns the logical name of the entity (_LOGICALNAME_).
''' </summary>
Public Const LogicalName As String = "_LOGICALNAME_"

Sample output

''' <summary>
''' Returns the logical name of the entity (account).
''' </summary>
Public Const LogicalName As String = "account"


CRM Code Generator - _PICKLIST_OPTIONS_ Placeholder

CRM Code Generator - _PICKLIST_OPTIONS_ Placeholder Stunnware

_PICKLIST_OPTIONS_ is replaced with an enumeration of available picklist options.

Note: It is important to enter a space between the comment operator and the term _PICKLIST_OPTIONS_.

C#
Sample definition

//_PICKLIST_PROPERTY_START
/// <summary>
/// _ATTRIBUTEDESCRIPTION_
/// </summary>
public int? _PICKLIST_PROPERTY {
get { return this.GetPicklist("_ATTRIBUTENAME_"); }
set { this.SetPicklist("_ATTRIBUTENAME_", value); }
}

public enum _PICKLIST_PROPERTYOptions {
 // _PICKLIST_OPTIONS_
}
//_PICKLIST_PROPERTY_END

Sample output

public enum IndustrycodeOptions {
Accounting = 1,
AgricultureAndNonPetrolNaturalResourceExtraction = 2,
BroadcastingPrintingAndPublishing = 3,
Brokers = 4,
BuildingSupplyRetail = 5,
BusinessServices = 6,
Consulting = 7,
ConsumerServices = 8,
DesignDirectionAndCreativeManagement = 9,
DistributorsDispatchersAndProcessors = 10,
DoctorSOfficesAndClinics = 11,
DurableManufacturing = 12,
EatingAndDrinkingPlaces = 13,
EntertainmentRetail = 14,
EquipmentRentalAndLeasing = 15,
Financial = 16,
FoodAndTobaccoProcessing = 17,
InboundCapitalIntensiveProcessing = 18,
InboundRepairAndServices = 19,
Insurance = 20,
LegalServices = 21,
NonDurableMerchandiseRetail = 22,
OutboundConsumerService = 23,
PetrochemicalExtractionAndDistribution = 24,
ServiceRetail = 25,
SIGAffiliations = 26,
SocialServices = 27,
SpecialOutboundTradeContractors = 28,
SpecialtyRealty = 29,
Transportation = 30,
UtilityCreationAndDistribution = 31,
VehicleRetail = 32,
Wholesale = 33
}

VB.NET
Sample definition

'_PICKLIST_PROPERTY_START
''' <summary>
''' _ATTRIBUTEDESCRIPTION_
''' </summary>
Public Property _PICKLIST_PROPERTY() As Nullable(Of Integer)
Get
Return Me.GetPicklist("_ATTRIBUTENAME_")
End Get
Set(ByVal value As Nullable(Of Integer))
Me.SetPicklist("_ATTRIBUTENAME_", value)
End Set
End Property

Public Enum _PICKLIST_PROPERTYOptions
Empty = 0 ' _REMOVE_
' _PICKLIST_OPTIONS_
End Enum
'_PICKLIST_PROPERTY_END

Sample output

Public Enum IndustrycodeOptions
Accounting = 1
AgricultureAndNonPetrolNaturalResourceExtraction = 2
BroadcastingPrintingAndPublishing = 3
Brokers = 4
BuildingSupplyRetail = 5
BusinessServices = 6
Consulting = 7
ConsumerServices = 8
DesignDirectionAndCreativeManagement = 9
DistributorsDispatchersAndProcessors = 10
DoctorSOfficesAndClinics = 11
DurableManufacturing = 12
EatingAndDrinkingPlaces = 13
EntertainmentRetail = 14
EquipmentRentalAndLeasing = 15
Financial = 16
FoodAndTobaccoProcessing = 17
InboundCapitalIntensiveProcessing = 18
InboundRepairAndServices = 19
Insurance = 20
LegalServices = 21
NonDurableMerchandiseRetail = 22
OutboundConsumerService = 23
PetrochemicalExtractionAndDistribution = 24
ServiceRetail = 25
SIGAffiliations = 26
SocialServices = 27
SpecialOutboundTradeContractors = 28
SpecialtyRealty = 29
Transportation = 30
UtilityCreationAndDistribution = 31
VehicleRetail = 32
Wholesale = 33
End Enum


CRM Code Generator - _PRIMARYFIELDPROPERTY_ Placeholder

CRM Code Generator - _PRIMARYFIELDPROPERTY_ Placeholder Stunnware

The _PRIMARYFIELDPROPERTY_ is replaced with the name of an entity's primary field.

C#
Sample definition

/// <summary>
/// Returns the entity's display name (_PRIMARYFIELDPROPERTY_)
/// </summary>
public override string ToString() {
return (this._PRIMARYFIELDPROPERTY_ == null) ? null : this._PRIMARYFIELDPROPERTY_.ToString();
}

Sample output

/// <summary>
/// Returns the entity's display name (Name)
/// </summary>
public override string ToString() {
 return (this.Name == null) ? null : this.Name.ToString();
}
VB.NET
Sample definition

''' <summary>
''' Returns the entity's display name (_PRIMARYFIELDPROPERTY_)
''' </summary>
Public Overrides Function ToString() As String
If (Me._PRIMARYFIELDPROPERTY_ Is Nothing) Then
Return Nothing
Else
Return Me._PRIMARYFIELDPROPERTY_.ToString()
End If
End Function

Sample output

''' <summary>
''' Returns the entity's display name (Name)
''' </summary>
Public Overrides Function ToString() As String
If (Me.Name Is Nothing) Then
Return Nothing
Else
Return Me.Name.ToString()
End If
End Function


CRM Code Generator - _PRIMARYKEYPROPERTY_ Placeholder

CRM Code Generator - _PRIMARYKEYPROPERTY_ Placeholder Stunnware

The _PRIMARYKEYPROPERTY_ is replaced with the name of an entity's primary key.

C#
Sample definition

/// <summary>
/// Gets or sets the primary key of this entity.
/// </summary>
public override System.Guid? Id {
get { return this._PRIMARYKEYPROPERTY_; }
set { this._PRIMARYKEYPROPERTY_ = value; }
}

Sample output

/// <summary>
/// Gets or sets the primary key of this entity.
/// </summary>
public override System.Guid? Id {
get { return this.Accountid; }
set { this.Accountid = value; }
}
VB.NET
Sample definition

''' <summary>
''' Gets or sets the primary key of this entity.
''' </summary>
Public Overrides Property Id() As Nullable(Of System.Guid)
Get
Return Me._PRIMARYKEYPROPERTY_
End Get
Set(ByVal value As Nullable(Of System.Guid))
Me._PRIMARYKEYPROPERTY_ = value
End Set
End Property
Sample output

''' <summary>
''' Gets or sets the primary key of this entity.
''' </summary>
Public Overrides Property Id() As Nullable(Of System.Guid)
Get
Return Me.Accountid
End Get
Set(ByVal value As Nullable(Of System.Guid))
Me.Accountid = value
End Set
End Property


CRM Code Generator - _PROPERTIES_ Placeholder

CRM Code Generator - _PROPERTIES_ Placeholder Stunnware

_PROPERTIES_ is replaced with appropriate code for all entity attributes. Each attribute corresponds to one property in the code. You should not move or remove this placeholder.


CRM Code Generator - _REFERENCEDTYPE_ Placeholder

CRM Code Generator - _REFERENCEDTYPE_ Placeholder Stunnware
_REFERENCEDTYPE_ is used in lookup properties. The code generator knows from the metadata, which entity is referenced in a lookup field and sets the entity type name accordingly.
C#
Sample definition

//_LOOKUP_PROPERTY_START
/// <summary>
/// _ATTRIBUTEDESCRIPTION_
/// </summary>
public _CLASSPREFIX_EntityReference _LOOKUP_PROPERTY {
get { return this.GetLookup("_ATTRIBUTENAME_", "_REFERENCEDTYPE_"); }
set { this.SetLookup("_ATTRIBUTENAME_", "_REFERENCEDTYPE_", value); }
}
//_LOOKUP_PROPERTY_END

Sample output

/// <summary>
/// Unique identifier of the primary contact for the account.
/// </summary>
public SwCrmEntityReference Primarycontactid {
 get { return this.GetLookup("primarycontactid", "contact"); }
 set { this.SetLookup("primarycontactid", "contact", value); }
}
VB.NET
Sample definition

'_LOOKUP_PROPERTY_START
''' <summary>
''' _ATTRIBUTEDESCRIPTION_
''' </summary>
Public Property _LOOKUP_PROPERTY() As _CLASSPREFIX_EntityReference
Get
Return Me.GetLookup("_ATTRIBUTENAME_", "_REFERENCEDTYPE_")
End Get
Set(ByVal value As _CLASSPREFIX_EntityReference)
Me.SetLookup("_ATTRIBUTENAME_", "_REFERENCEDTYPE_", value)
End Set
End Property
'_LOOKUP_PROPERTY_END

Sample output

''' <summary>
''' Unique identifier of the primary contact for the account.
''' </summary>
Public Property Primarycontactid() As SwCrmEntityReference
 Get
Return Me.GetLookup("primarycontactid", "contact")
End Get
Set(ByVal value As SwCrmEntityReference)
Me.SetLookup("primarycontactid", "contact", value)
End Set
End Property


CRM Code Generator - _REMOVE_ Placeholder

CRM Code Generator - _REMOVE_ Placeholder Stunnware
Any line ending with _REMOVE_ is removed from the generated code. For instance, the next two lines are contained in the base class template:

protected string _PRIMARYFIELDPROPERTY_; // _REMOVE_
protected System.Guid? _PRIMARYKEYPROPERTY_; // _REMOVE_

The placeholders _PRIMARYFIELDPROPERTY_ and _PRIMARYKEYPROPERTY_ are used in the class template. Defining them in the base class ensures that you can compile the template classes, but they won't show up in the final code.

C# |
Sample definition | protected string _PRIMARYFIELDPROPERTY_; // _REMOVE_
Sample output | The entire line is removed from the output.
VB.NET |
Sample definition | Protected _PRIMARYFIELDPROPERTY_ As String '_REMOVE_
Sample output | The entire line is removed from the output.


CRM Code Generator - _REMOVE_IN_BASE_CLASS_START_ & _REMOVE_IN_BASE_CLASS_END_ Placeholders

CRM Code Generator - _REMOVE_IN_BASE_CLASS_START_ & _REMOVE_IN_BASE_CLASS_END_ Placeholders Stunnware

Everything between _REMOVE_IN_BASE_CLASS_START_ and _REMOVE_IN_BASE_CLASS_END_, including the comments itself, is removed from the base class after code generation has finished. The code serves as a template only and is not needed in the final output.

Note: You usually do not need to modify this content.

C#
Sample definition

//_REMOVE_IN_BASE_CLASS_START_
C# Code
//_REMOVE_IN_BASE_CLASS_END_
Sample output | The entire code is removed from the output.
VB.NET
Sample definition

'_REMOVE_IN_BASE_CLASS_START_
VB.NET Code
'_REMOVE_IN_BASE_CLASS_END_
Sample output | The entire code is removed from the output.


CRM Code Generator - _STATE_ENUM_ Placeholder

CRM Code Generator - _STATE_ENUM_ Placeholder Stunnware

_STATE_ENUM_ is replaced with an enumeration of the available entity states.

Note: It is important to enter a space between the comment operator and the term _STATE_ENUM_.

C#
Sample definition

public enum _CLASSNAME_State {
// _STATE_ENUM_
}
Sample output

public enum SwCrmAccountState {
Active = 0,
Inactive = 1
}
VB.NET
Sample definition

Public Enum _CLASSNAME_State
Dummy = 0 ' _REMOVE_
' _STATE_ENUM_
End Enum
Sample output

Public Enum SwCrmAccountState
Active = 0
Inactive = 1
End Enum


CRM Code Generator - _STATUS_ENUM_ Placeholder

CRM Code Generator - _STATUS_ENUM_ Placeholder Stunnware

_STATUS_ENUM_ is replaced with an enumeration of the available entity statuses.

Note: It is important to enter a space between the comment operator and the term _STATUS_ENUM_.

C#
Sample definition

public enum _CLASSNAME_Status {
// _STATUS_ENUM_
}
Sample output

public enum SwCrmInvoiceStatus {
ActiveNew = 1,
ActivePartiallyShipped = 2,
ActiveBilled = 4,
ActiveBookedAppliesToServices = 5,
ActiveInstalledAppliesToServices = 6,
ClosedCanceledDeprecated = 3,
ClosedPaidInFullDeprecated = 7,
PaidComplete = 100001,
PaidPartial = 100002,
CanceledCanceled = 100003
}
VB.NET
Sample definition

Public Enum _CLASSNAME_Status
Dummy = 0 ' _REMOVE_
' _STATUS_ENUM_
End Enum
Sample output

Public Enum SwCrmInvoiceStatus
ActiveNew = 1
ActivePartiallyShipped = 2
ActiveBilled = 4
ActiveBookedAppliesToServices = 5
ActiveInstalledAppliesToServices = 6
ClosedCanceledDeprecated = 3
ClosedPaidInFullDeprecated = 7
PaidComplete = 100001
PaidPartial = 100002
CanceledCanceled = 100003
End Enum


CRM Code Generator - _TARGETNAMESPACE_ Placeholder

CRM Code Generator - _TARGETNAMESPACE_ Placeholder Stunnware

The _TARGETNAMESPACE_ refers to the target namespace you have specified in the project settings.

C#
Sample definition

namespace _TARGETNAMESPACE_ {
 //_CLASSES_
}
Sample output

namespace Stunnware.Crm4.WebServiceClasses {
/// <summary>
/// Business that represents a customer or potential customer. The company that is billed in business transactions.
/// </summary>
public partial class SwCrmAccount : Stunnware.Crm4.WebServiceClasses.SwCrmEntity {
}
}
VB.NET
Sample definition

Namespace _TARGETNAMESPACE_
 '_CLASSES_
End Namespace
Sample output

Namespace Stunnware.Crm4.WebServiceClasses
''' <summary>
''' Business that represents a customer or potential customer. The company that is billed in business transactions.
''' </summary>
Partial Public Class SwCrmAccount
 Inherits Stunnware.Crm4.WebServiceClasses.SwCrmEntity
 End Class
End Namespace


CRM Code Generator - Introduction

CRM Code Generator - Samples Stunnware

The following code snippets show how to use the generated code. The syntax is based on the output of the standard templates. If you are using modified templates, your code may be different. The code generator project used the following settings:

Only accounts and contacts were created. The following is sample code showing the general usage. It's not meant to be documentation of the generated code though. The Service property (this.Service or Me.Service) is a properly configured Microsoft.Crm.SdkTypeProxy.CrmService instance.

Retrieving data

C#

private void RetrieveAccounts() {
QueryExpression query = new QueryExpression(Account.LogicalName);
query.ColumnSet = new ColumnSet(new string[] { Account.Attributes.Name });

if (this.textBoxSearchFor.Text.Length > 0) {
query.Criteria.AddCondition(Account.Attributes.Name, ConditionOperator.Like, this.textBoxSearchFor.Text + "%");
}

List<Account> accounts = Account.RetrieveMultiple(this.Service, query);
this.listBoxResult.Items.Clear();

 foreach (Account acct in accounts) {
this.listBoxResult.Items.Add(acct);
}
}

private void RetrieveContacts() {
QueryExpression query = new QueryExpression(Contact.LogicalName);
query.ColumnSet = new ColumnSet(new string[] { Contact.Attributes.Fullname });

if (this.textBoxSearchFor.Text.Length > 0) {
query.Criteria.AddCondition(Contact.Attributes.Firstname, ConditionOperator.Like, this.textBoxSearchFor.Text + "%");
query.Criteria.AddCondition(Contact.Attributes.Lastname, ConditionOperator.Like, this.textBoxSearchFor.Text + "%");
query.Criteria.AddCondition(Contact.Attributes.Fullname, ConditionOperator.Like, this.textBoxSearchFor.Text + "%");
query.Criteria.FilterOperator = LogicalOperator.Or;
}

List<Contact> contacts = Contact.RetrieveMultiple(this.Service, query);
this.listBoxResult.Items.Clear();

 foreach (Contact c in contacts) {
this.listBoxResult.Items.Add(c);
}
}

VB.NET

Private Sub RetrieveAccounts()
 Dim query As New QueryExpression(Account.LogicalName)
query.ColumnSet = New ColumnSet(New String() {Account.Attributes.Name})

 If (Me.textBoxSearchFor.Text.Length > 0) Then
query.Criteria.AddCondition(Account.Attributes.Name, ConditionOperator.Like, Me.textBoxSearchFor.Text + "%")
 End If

Dim accounts As List(Of Account) = Account.RetrieveMultiple(Me.Service, query)
 Me.listBoxResult.Items.Clear()

 For Each acct As Account In accounts
 Me.listBoxResult.Items.Add(acct)
 Next
End Sub

Private Sub RetrieveContacts()
 Dim query As New QueryExpression(Contact.LogicalName)
query.ColumnSet = New ColumnSet(New String() {Contact.Attributes.Fullname})

 If (Me.textBoxSearchFor.Text.Length > 0) Then
query.Criteria.AddCondition(Contact.Attributes.Firstname, ConditionOperator.Like, Me.textBoxSearchFor.Text + "%")
query.Criteria.AddCondition(Contact.Attributes.Lastname, ConditionOperator.Like, Me.textBoxSearchFor.Text + "%")
query.Criteria.AddCondition(Contact.Attributes.Fullname, ConditionOperator.Like, Me.textBoxSearchFor.Text + "%")
query.Criteria.FilterOperator = LogicalOperator.Or
 End If

Dim contacts As List(Of Contact) = Contact.RetrieveMultiple(Me.Service, query)
 Me.listBoxResult.Items.Clear()

 For Each c As Contact In contacts
 Me.listBoxResult.Items.Add(c)
 Next
End Sub

Creating and updating data

C#

private
void
buttonCreate_Click(object
sender, EventArgs e)
{
Account
acct = new
Account();
acct.Name = this.textBoxAccountName.Text;
acct.Id = acct.Create(this.Service);

Contact
contact = new
Contact();
contact.Lastname = this.textBoxContactLastName.Text;
contact.Firstname = this.textBoxContactFirstName.Text;
contact.Parentcustomerid = acct.ToReference();
contact.Id = contact.Create(this.Service);

Account
acctUpdate = new
Account();
acctUpdate.Id = acct.Id;
acctUpdate.Primarycontactid = contact.ToReference();
acctUpdate.Update(this.Service);
}

VB.NET

Private Sub buttonCreate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonCreate.Click
Dim acct As New Account()
acct.Name = Me.textBoxAccountName.Text
acct.Id = acct.Create(Me.Service)

Dim contact As New Contact
contact.Lastname = Me.textBoxContactLastName.Text
contact.Firstname = Me.textBoxContactFirstName.Text
contact.Parentcustomerid = acct.ToReference()
contact.Id = contact.Create(Me.Service)

Dim acctUpdate As New Account()
acctUpdate.Id = acct.Id
acctUpdate.Primarycontactid = contact.ToReference()
acctUpdate.Update(Me.Service)
End Sub

Deleting data

C#

private void buttonDelete_Click(object sender, EventArgs e) {
 if (this.listBoxResult.SelectedItems != null) {
foreach (Entity item in this.listBoxResult.SelectedItems) {
item.Delete(this.Service);
}
}
}

VB.NET

Private Sub buttonDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonDelete.Click
 If (Not (Me.listBoxResult.SelectedItems Is Nothing)) Then
For Each item As Entity In Me.listBoxResult.SelectedItems
item.Delete(Me.Service)
Next
End If
End Sub

Activating and Deactivating

C#

private void buttonDeactivate_Click(object sender, EventArgs e) {
if (this.listBoxResult.SelectedItems != null) {
foreach (Entity item in this.listBoxResult.SelectedItems) {
item.Deactivate(this.Service);
}
}
}

private void buttonActivate_Click(object sender, EventArgs e) {
if (this.listBoxResult.SelectedItems != null) {
foreach (Entity item in this.listBoxResult.SelectedItems) {
item.Activate(this.Service);
}
}
}

VB.NET

Private Sub buttonDeactivate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonDeactivate.Click
 If Not (Me.listBoxResult.SelectedItems Is Nothing) Then
For Each item As Entity In Me.listBoxResult.SelectedItems
item.Deactivate(Me.Service)
Next
End If
End Sub

Private Sub buttonActivate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonActivate.Click
If Not (Me.listBoxResult.SelectedItems Is Nothing) Then
For Each item As Entity In Me.listBoxResult.SelectedItems
item.Activate(Me.Service)
 Next
End If
End Sub


CRM Documentation - Introduction

CRM Documentation - Introduction Stunnware

The Documentation module is meant as a tool to create technical documentations of a CRM organization. It uses the Microsoft HTML Help Compiler to create a compiled HTML file (chm extension) that you can deliver to customers or use it for your own reference.

Though there is a complex example shipped with the product, you are totally free in defining the content and look and feel. In summary, the CRM documentation extension allows:

  • Selecting the entities to document. This can be all entities or a subset only.

  • Defining the structure of the Table of Contents.

  • Using templates to create documentation for entities and attributes.

  • Merging information from the CRM Metadata and customizations.

  • Documenting script source, including all OnLoad, OnSave and OnChange events, plus CRM scripts used by CRM internally.

  • Builds a help index automatically.

  • Optionally compiles the HTML source files and views the final help file.

You need the Microsoft HTML Help Compiler on your system to compile the source files. It is included in the HTML Help Workshop, which you can download at http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en.

Note: The CRM Documentation module requires the Professional Edition to be fully functional. It's limited to accounts and contacts in the Community Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules

  • Configuring the HTML Compiler

  • Creating a new Help project

  • Project File XML Reference

  • Table of Contents XML Reference


CRM Documentation - Configuring the HTML Compiler

Configuring the HTML Compiler Stunnware

To create a compiled compiled HTML file (chm extension), you need the Microsoft HTML Help Compiler on your system. It is included in the HTML Help Workshop, which you can download at http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en.

Once you have installed it, you must configure the HTML compiler. Click on the Tools main menu and select Options. Then select the Settings node inside of the Documentation category:

All you have to do is selecting the hhc.exe file inside of the HTML Help Workshop's installation folder. The Stunnware Tools try to retrieve the proper location from the registry, but if it fails, you have to provide it manually. Make sure to select hhc.exe and not hhw.exe.

Note: There is no OK button in this dialog. All changes you make to the configuration are saved immediately.


CRM Documentation - Creating a new Help Project

Creating a new Help Project Stunnware

To create a help project, open the CRM Documentation page and click the New button. A Save As dialog appears, prompting for the location of the new project file:

Save new project

Select the folder and specify the file name. The default extension used is SWHHP, which is short for Stunnware HTML Help Project. Click the Save button and you are presented with the project settings window.

The Options tab

Most of the settings used to create the final help file are defined in external files. The options simply reference these files and specify general options.

Input & Output

The Input Folder defines the location of the input files needed to create the help file. A sample input is shipped with the product and creates a help file in the MSDN style. For a quick start, copy the contents of the Templates\Help Generator\MSDN sub-folder of the directory where you have installed the Stunnware Tools application to a location on your hard drive and select it as the input folder. You can either type in the path directly or select it from a folder list by clicking the Template Folder button:

Specify the Input Folder

The Output Folder is the location where HTML files are generated and the final help is created. It can be any folder on your hard drive or even a network drive. To keep things together, create the output folder in the same directory where you added the input folder. You can either type in the path directly or select it from a folder list by clicking the Output Folder button:

Select the Output Folder

The Help File denotes the name of the final help file, including the chm extension. It is created in the output folder, so you only specify the file name, but not the path. For instance, select Crm Help.chm:

Help File Creation

The options in the Help File Creation group specify what actions to perform in a build process. If Create HTML Content Files is checked, the entire documentation is rebuilt. Depending on the declarations made in the input files, this can create some thousand HTML files. When designing a help file and working on the table of contents, you don't want this process happening every time, because it may take some minutes to complete. Checking the Compile HTML project invokes the HTML compiler after the input is processed, whether you have created the content files or not. Finally, View Help File after compilation is a convenient way to open the compiled help file after the build process has finished.

The Build tab

The Build tab shows the progress of a build process. When you start a build, this tab is shown automatically.

The Compile tab

The Compile tab shows the progress of the compilation process and is activated after all input files were processed.

Ribbon buttons

The buttons should be self-explanatory: Click Save or Save As to save the project. Build Help File starts the build process, executing all actions you have selected in the Help File Creation group.

To open a previously saved project, either click Open to browse your drives or Recent to open a recently used project.


CRM Documentation - Project File XML Reference

CRM Documentation - Project File XML Reference Stunnware

The starting point of each documentation project is the project XML file. It is always named HTML Help Project.xml and must be available in the Input Folder:

In the above project, the full path to the project XML file is C:\Help\Input\HTML Help Project.xml.

Project XML Structure

The content of the project XML file mainly consists of elements used by the Microsoft HTML compiler and unless you are familiar with an HTML Help project file, we recommend to only change the options that are explained in this documentation. Please refer to the Microsoft HTML Help documentation for a description of the other settings.

<HtmlHelpProject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AutoIndex>true</AutoIndex>
<BinaryToc>true</BinaryToc>
<Compatibility>1.1 or later</Compatibility>
<CompiledHtmlFile>help.chm</CompiledHtmlFile>
<TableOfContentsFile>Table Of Contents.xml</TableOfContentsFile>
<Default Topic>entityList.htm</DefaultTopic>
<DefaultWindow>Default</DefaultWindow>
<DisplayCompileProgress>true</DisplayCompileProgress>
<ErrorLogFile>help.log</ErrorLogFile>
<FullTextSearch>true</FullTextSearch>
<IndexFile>index.hhk</IndexFile>
<Language>0x409 English (United States)</Language>
<Title>Generated Help</Title>
<SupportFiles>
<Include inputDir="." outputDir="." mask="help.css" />
<Include inputDir="images" outputDir="images" mask="*.*" recursive="true" />
</SupportFiles>
</HtmlHelpProject>

The lines marked in yellow are what should most interest you.

CompiledHtmlFile

This is the file name of the generated compiled HTML file. The value is replaced with the name you have specified in the Help File textbox in the CRM Documentation Project Form. The initial value stored in the project XML file will not be used.

TableOfContentsFile

A help file always has a table of contents, which is stored in an external file. The value you specify is the name of a file in the Input Folder. Using C:\Help\Input as the input folder and the above listed project XML settings, the full path of the TOC file is C:\Help\Input\Table Of Contents.xml.

For more information about the TOC, see the Table of Contents Reference.

Title

This is the title displayed in the generated help file. You want to change it to My Project Documentation or something else better describing the content.

SupportFiles

Besides HTML pages, whether generated or not, you usually have external resources, like images, style sheets or even script files. The Include statements define the names of such files that should be copied from the Input Folder to the Output Folder when building a help file. The following attributes are available:

inputDir: a path relative to the Input Folder. Use a single dot to denote the input folder itself, otherwise specify the name of a sub-folder.

outputDir: a path relative to the Output Folder. Use a single dot to denote the output folder itself, otherwise specify the name of a sub-folder.

mask: a file mask used to select files, including wildcards. For instance, *.* selects all files, *.css select all files with the css extension and help.css only selects the file named helps.css.

recursive: if set to true, all sub-folders are processed as well.

DefaultTopic

The topic to be displayed by default when opening the help file. Must be a path relative to the output directory and can point to any HTML file being created when building the output. It can also be the name of a file available in the support files, as these are copied to the output directory as well.


CRM Documentation - Table of Contents File XML Reference

CRM Documentation - Table of Contents File XML Reference Stunnware

The Table of Contents (TOC) defines what elements to include in the help file, what chapters and topics exists and how the TOC is organized in general. Writing a TOC is both, defining a part of the help file and defining how to access the data in CRM. The name of the TOC file is defined in the Project XML File.

A sample Table of Contents file

To better understand the various parts of a TOC, let's look at a real-world example used by the :

<?xml
version="1.0"
encoding="utf-8"
?>
<Toc
windowStyles="0x800025"
articleImage="11">
<Selection
type="Entity"
name="EntitiesToProcess">
<Condition
property="DisplayName"
not="true"
op="isNull"
/>
</Selection>
<Selection
type="Entity"
name="FilteredLookupEntities">
<Condition
property="LogicalName"
op="startsWith"
value="sw_"
/>
<Condition
property="LogicalName"
not="true"
op="eq"
value="sw_picklist"
/>
<Condition
property="LogicalName"
not="true"
op="eq"
value="sw_softwareproduct"
/>
<Condition
property="DisplayName"
not="true"
op="isNull"
/>
</Selection>
<Selection
type="Entity"
name="AllVisibleEntities">
<Condition
property="DisplayName"
not="true"
op="isNull"
/>
</Selection>
<Selection
type="Attribute"
name="AllAttributes">
<Condition
property="AttributeOf"
op="isNull"
/>
</Selection>
<Selection
type="Event"
name="AllEvents">
</Selection>
<Chapter
title="Entities
and Attributes"
input="entityList.xml"
output="entityList.htm"
parse="true">
<For
var="@Entity1"
in="EntitiesToProcess"
sortBy="LogicalName"
sortOrder="ascending">
<Chapter
title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">
<Chapter
title="Attributes"
input="attributeList.xml"
output="$(@Entity1.LogicalName)\attributes.htm"
parse="true">
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)"
input="attribute.xml"
output="$(@Entity1.LogicalName)\$(@Attribute1.LogicalName).htm"
parse="true"
/>
</For>
</Chapter>
<If
var="@Entity1"
method="HasEvents">
<Chapter
title="Events"
input="eventList.xml"
output="$(@Entity1.LogicalName)\events.htm"
parse="true">
<For
var="@FormEvent"
in="AllEvents"
of="@Entity1"
sortBy="Name"
sortOrder="ascending">
<Article
title="Form
$(@FormEvent.Name)"
input="formEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm"
parse="true"
/>
</For>
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<For
var="@FieldEvent"
in="AllEvents"
of="@Attribute1"
sortBy="Name"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)
$(@FieldEvent.Name)"
input="fieldEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@Attribute1.LogicalName)_$(@FieldEvent.UniqueName).htm"
parse="true"
/>
</For>
</For>
</Chapter>
</If>
</Chapter>
</For>
</Chapter>
</Toc>

A TOC file used by the Microsoft HTML compiler looks quite different:

<html>
<head>
<meta name="GENERATOR" content="Stunnware Documentation Generator" />
</head>
<body>
<object type="text/site properties">
<param name="Window Styles" value="0x800025" />
</object>
<ul>
<li>
<object type="text/sitemap">
<param name="Name" value="Entities and Attributes" />
<param name="Local" value="entityList.htm" />
</object>
</li>
<ul>
<li>
<object type="text/sitemap">
<param name="Name" value="account" />
<param name="Local" value="account\entity.htm" />
</object>
</li>
<ul>
<li>
<object type="text/sitemap">
<param name="Name" value="Attributes" />
<param name="Local" value="account\attributes.htm" />
</object>
</li>
<ul>
<li>
<object type="text/sitemap">
<param name="Name" value="accountcategorycode" />
<param name="Local" value="account\accountcategorycode.htm" />
<param name="ImageNumber" value="11" />
</object>
</li>
...

During the build process, a TOC file compatible with the Microsoft Help Compiler is created and the TOC XML file defines it's entire structure.

The TOC root node

The root node defines parameters used by the Microsoft HTML Compiler:

<Toc windowStyles="0x800025" articleImage="11">

The above sets two parameters: windowStyles corresponds to the Window Styles parameter and is a bitmask defining various styles of the final HTML file. Instead of trying to find all possible values that can be used, it's much easier to open the generated help file project (hhp extension) with the Microsoft HTML Help Workshop application. You can make all required changes in this application and if you find a different value in the Window Styles parameter afterwards, simply use this new value in the TOC XML file.

The articleImage defines the default icon to be used for help topics and corresponds to the ImageNumber parameter. Again, use the Microsoft HTML Help Workshop application to find icons with a different index that better suit your needs.

In general, you don't want to change these values unless you are very comfortable with the Microsoft HTML Help Workshop. If this is the first time you are creating help files, then don't worry about them at all.

Child Nodes

Everything inside the Toc root node is used to define the TOC. Use the following links for further information:

  • Using Selections - Defining which entities, attributes and events to include

  • Chapters and Topics - Defining the content of the TOC

  • For Loops - Creating content for multiple items

  • Conditional statements (If)


CRM Documentation - Using Selections

CRM Documentation - Using Selections Stunnware

If you had to manually create a help file containing all entities and all attributes, you probably give up after a short time, because even writing the TOC would take forever. And you will find that your repeating the same entries like chapters and topics over and over. The whole idea of the documentation module is automating this process. However, we don't know what you want to see included in your help file. It may be all entities and all attributes, but maybe it's more like custom entities and custom attributes of system entities. Whatever it is needs to be defined and this is done with selections.

A sample selection

<Selection
type="Entity"
name="FilteredLookupEntities">
<Condition
property="LogicalName"
op="startsWith"
value="sw_"
/>
<Condition
property="LogicalName"
not="true"
op="eq"
value="sw_picklist"
/>
<Condition
property="LogicalName"
not="true"
op="eq"
value="sw_softwareproduct"
/>
<Condition
property="DisplayName.UserLocLabel.Label"
not="true"
op="isNull"
/>
</Selection>

The above selection refers to entites (type = Entity) and is named FilteredLookupEntities. It contains all entities matching the specified conditions, which is

  • The entity's logical name starts with sw_.
  • The entity's logical name is not sw_picklist.
  • The entity's logical name is not sw_softwareproduct.
  • The entity has a display name.

All conditions must be met. In other words, the selection contains all custom entities (because I'm using the sw customizaion prefix on my system), except sw_picklist and sw_softwareproduct. To not include helper entities, the last condition ensures that only entities with a display name are added to the help file.

The Selection element

Each selection has a name and a type and they are referenced in a For Loop like this:

<For
var="@Entity1"
in="FilteredLookupEntities"
sortBy="LogicalName"
sortOrder="ascending">

You can choose any name for a selection, but it must be unique in the entire file. The type is either Entity, Attribute, AttributeOptions or Event. AttributeOptions selects all options of a picklist, state, status or boolean attribute. Conditions and sort flags are not used in an AttributeOptions selection.

Conditions

Conditions define which objects are included in a selection. If you don't specify a condition, then you get a selection with all entities, attributes or events. Attributes and event selections do always have a context to an entity though.

The property is the value you want to check and you are using .NET properties. For example, LogicalName in an entity selection accesses the LogicalName property of an EntityMetadata instance and DisplayName.UserLocLabel.Label accesses DisplayName.UserLocLabel.Label. As selections are always used in conjunction with For Loops, the following code snippet may help you to better understand the overall process:

function List<EntityMetadata>
GetEntities() {
List<EntityMetadata>entitites
= new List<EntityMetadata>();

foreach(EntityMetadata
entity in AllEntities) {
if (entity.LogicalName.StartsWith("sw_")
&&
(entity.LogicalName
!= "sw_picklist") &&
(entity.LogicalName
!= "sw_softwareproduct") &&
(entity.DisplayName
!= null) && entity.DisplayName.UserLocLabel !=
null) && entity.DisplayName.UserLocLabel.Label !=
null)) {
entities.Add(entity);
}
}

return entities;
}

List<EntityMetadata>
FilteredLookupEntities = GetEntities();
FilteredLookupEntities.Sort(); //sort by logical name,
ascending

foreach(EntityMetadata
Entity1 in FilteredLookupEntities) {
//process toc
}

The condition operator

The condition operator is specified in the op attribute and can have one of these values:

  • eq - Checks if two values are equale
  • startsWith - Checks if a string value starts with another value
  • isNull - Checks for a null value

Using the "not" attribute

When setting the not attribute to true, then the entire condition is negated and the condition operators change their meaning:

  • eq - Checks if two values are not equal
  • startsWith - Checks if a string value does not start with another value
  • isNull - Checks if a value is not null

Specifying the comparison value

When using eq or startsWith, you must specify the comparison value in the value attribute. The isNull condition operator does not required this attribute.


CRM Documentation - Chapters and Topics

CRM Documentation - Chapters and Topics Stunnware

A help file is usually organized in chapters. Though optional, it makes sense to structure the content to make it easier for the reader to follow your thoughts. Like a disk drive, where you are using folders and files, where each folder can have sub-folders, the Table of Contents define chapters and topics, where each chapter can contain topics or sub-chapters.

A topic represents a single article and must be bound to an HTML page. A chapter is a container for other topics and is optionally bound to an HTML file. Though pretty much the same, the TOC XML file uses Chapter and Article nodes, because it's easier to understand when managing the XML content.

Below is an example of a typical help file:

<Chapter
title="Entities
and Attributes"
input="entityList.xml"
output="entityList.htm"
parse="true">
<For
var="@Entity1"
in="EntitiesToProcess"
sortBy="LogicalName"
sortOrder="ascending">
<Chapter
title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">
<Chapter
title="Attributes"
input="attributeList.xml"
output="$(@Entity1.LogicalName)\attributes.htm"
parse="true">
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)"
input="attribute.xml"
output="$(@Entity1.LogicalName)\$(@Attribute1.LogicalName).htm"
parse="true"
/>
</For>
</Chapter>
<If
var="@Entity1"
method="HasEvents">
<Chapter
title="Events"
input="eventList.xml"
output="$(@Entity1.LogicalName)\events.htm"
parse="true">
<For
var="@FormEvent"
in="AllEvents"
of="@Entity1"
sortBy="Name"
sortOrder="ascending">
<Article
title="Form
$(@FormEvent.Name)"
input="formEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm"
parse="true"
/>
</For>
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<For
var="@FieldEvent"
in="AllEvents"
of="@Attribute1"
sortBy="Name"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)
$(@FieldEvent.Name)"
input="fieldEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@Attribute1.LogicalName)_$@FieldEvent.UniqueName).htm"
parse="true"
/>
</For>
</For>
</Chapter>
</If>
</Chapter>
</For>
</Chapter>

The above structure creates an expandable table of contents similar to the following:

Defining chapters

A chapter is defined by a Chapter element and contains the following attributes and child elements:

Attributes

The title attribute defines the display name of the chapter. For instance, the Entities and Attributes chapter you see in the image above also has a title of Entities and Attributes in the XML file. The title can be a static text, a dynamic text or a combination of both. For information about how to build dynamic text, please refer to Dynamic Text.

The input attribute holds the name of an input file in the input folder (see Creating a new Help Project for more information). You can use Dynamic Text to build the input file name, though this is usually used in the output attribute. The input attribute can contain folder names like "account/account.xml", but is always relative to the input folder. When specifying an input file, you must specify an output file as well.

The output attribute holds the name of an output file in the output folder (see Creating a new Help Project for more information). You can use Dynamic Text to build the output file name, which is essential when running inside a For Loop. Like in the input, the output attribute can contain folder names like "account/account.xml", but is always relative to the output folder. When specifying an output file, you must specify an input file as well.

The parse attribute defines whether the input file is parsed or not. If set to true, the referenced input file must be valid XML and can contain the same expressions you are using the TOC and you also have access to the variables defined in the For Loop statements. This context is required to dynamically create the final HTML pages.

Note: Chapters do not require a bound HTML page, so it is legal to omit the input and output attributes. Either both attributes are defined, or none of them.

Valid Child Elements

A chapter can contain any of the following child elements:

  • Chapter
  • Article
  • Selection
  • For
  • If

Defining articles

An article (or topic) is identified by an Article element. It uses the same attributes as a chapter, so please refer to the Attributes section above. Articles, however, do not contain any child elements. An article is the last element in a node hierarchy.

Another difference to a chapter, is that both the input and output attributes must be set, because an article always has an associated HTML page. Otherwise your final help file will be incomplete.

Valid Child Elements

An article does not have any child elements.


CRM Documentation - For Loops

CRM Documentation - For Loops Stunnware

To automate the build process, you are defining Selections, that tell the documentation extension which items to process. In the TOC you are referencing these selections in For-elements. It has the same meaning as you know from any programming language and processes the child nodes and instructions for each element contained in the selection.

Below is an example of a typical help file:

<Chapter
title="Entities
and Attributes"
input="entityList.xml"
output="entityList.htm"
parse="true">
<For
var="@Entity1"
in="EntitiesToProcess"
sortBy="LogicalName"
sortOrder="ascending">
<Chapter
title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">
<Chapter
title="Attributes"
input="attributeList.xml"
output="$(@Entity1.LogicalName)\attributes.htm"
parse="true">
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)"
input="attribute.xml"
output="$(@Entity1.LogicalName)\$(@Attribute1.LogicalName).htm"
parse="true"
/>
</For>
</Chapter>
<If
var="@Entity1"
method="HasEvents">
<Chapter
title="Events"
input="eventList.xml"
output="$(@Entity1.LogicalName)\events.htm"
parse="true">
<For
var="@FormEvent"
in="AllEvents"
of="@Entity1"
sortBy="Name"
sortOrder="ascending">
<Article
title="Form
$(@FormEvent.Name)"
input="formEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm"
parse="true"
/>
</For>
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<For
var="@FieldEvent"
in="AllEvents"
of="@Attribute1"
sortBy="Name"
sortOrder="ascending">
<Article
title="$(@Attribute1.LogicalName)
$(@FieldEvent.Name)"
input="fieldEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@Attribute1.LogicalName)_$@FieldEvent.UniqueName).htm"
parse="true"
/>
</For>
</For>
</Chapter>
</If>
</Chapter>
</For>
</Chapter>

You can have multiple For-elements in a single chapter and you can also have nested For-statements. In the above example, the green chapters are created for each entity contained in the selection named EntitiesToProcess. The second chapter (named Attributes) contains the blue article for each attribute in the AllAttributes selection. As attributes and scripts do always need an entity context, the of attribute references the variable used in the first For-element (@Entity1).

The remaining For-elements follow these same rules. For instance, the red article is created for each event (AllEvents selection) of all attributes (AllAttributes selection) of all entities to process (EntitiesToProcess selection).

The result of the above processing instructions is similar to the following:

Defining For-Loops

A For-Loop is defined by a For element and contains the following attributes and child elements:

Attributes

The var attribute defines the name of a loop-variable. You reference this variable in the table of contents and in the input files that are used to create the HTML files. The variable name must be unique in the entire context of the for-definition. Just like in any other programming language, you cannot declare the same variable twice.

The in attribute references the name of a Selection, which can be a set of entities, attributes or events. If the selection contains attributes, then you must specify a variable in the of attribute and this variable must hold an entity. If the selection contains events, then the of attribute must point to a variable referencing either an entity or an attribute. Depending on what it specified, you are accessing the entity events (OnLoad, OnSave) or the field events (OnChange). You will see some hidden scripts though when looking at the generated help file.

Note: the of attribute is not used when referencing an entity selection.

The sortBy and sortOrder attributes specify how the elements in the selection are ordered in the help file. You usually choose the logical name or display name for ordering, but can select any valid property of the CRM metadata objects. The sortOrder attribute defaults to ascending, if not specified. Valid values are ascending and descending. There is no default value for the sortBy attribute though. If you don't specify it, the resulting help file will be unordered.

Valid Child Elements

A For-Element can contain any of the following child elements:

  • Chapter
  • Article
  • Selection
  • For
  • If


CRM Documentation - Conditional Statements

CRM Documentation - Conditional Statements Stunnware

Conditional statements are used to create alternate items in the Table of Contents or alternate content in HTML pages. While general filtering is done through Selections, you sometimes have to compare values at runtime that to create a better help.

Below is an example of a typical help file:

<Chapter
title="Entities
and Attributes"
input="entityList.xml"
output="entityList.htm"
parse="true">
<For
var="@Entity1"
in="EntitiesToProcess"
sortBy="LogicalName"
sortOrder="ascending">
<Chapter title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">
<Chapter
title="Attributes"
input="attributeList.xml"
output="$(@Entity1.LogicalName)\attributes.htm"
parse="true">
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<Article title="$(@Attribute1.LogicalName)"
input="attribute.xml"
output="$(@Entity1.LogicalName)\$(@Attribute1.LogicalName).htm"
parse="true"
/>
</For>
</Chapter>
<If
var="@Entity1"
method="HasEvents">
<Chapter
title="Events"
input="eventList.xml"
output="$(@Entity1.LogicalName)\events.htm"
parse="true">
<For
var="@FormEvent"
in="AllEvents"
of="@Entity1"
sortBy="Name"
sortOrder="ascending">
<Article
title="Form
$(@FormEvent.Name)"
input="formEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm"
parse="true"
/>
</For>
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<For
var="@FieldEvent"
in="AllEvents"
of="@Attribute1"
sortBy="Name"
sortOrder="ascending">
<Article title="$(@Attribute1.LogicalName)
$(@FieldEvent.Name)"
input="fieldEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@Attribute1.LogicalName)_$@FieldEvent.UniqueName).htm"
parse="true"
/>
</For>
</For>
</Chapter>
</If>
</Chapter>
</For>
</Chapter>

The If-statement checks whether the entity (@Entity1, defined in the green For-statement) has events or not. HasEvents is a special method that is not available in the CRM metadata and therefore cannot be used in a selection. It is calculated at runtime and the above TOC uses it to decide whether an Events chapter is added to the TOC or not.

In the above help file, the Events chapter was added, because three events exist in the account entity. You only want the Events chapter to be included though, if there is at least one event. The If-statement is used exactly for such scenarios, but is not limited to it.

Defining If-Statements

A conditional expression is defined by an If element and contains the following attributes and child elements:

Attributes

The var attribute defines the name of a loop-variable. You reference this variable in the table of contents and in the input files that are used to create the HTML files. The variable name must be unique in the entire context of the for-definition. Just like in any other programming language, you cannot declare the same variable twice.

The method attribute defines the operation to execute. It can be one of the following:

  • HasEvents: Evaluates if an entity or attribute has events. When passing an entity reference in the var attribute, the method checks for events in the entire CRM form and is identical to calling HasFormEvents. When passing an attribute reference, the method checks for CRM field events specific to the referenced attribute.
  • HasFormEvents: The method checks if there is at least one form or field event in the entire CRM form. You must pass an entity reference in the var attribute.

Valid Child Elements

An If-Element can contain any of the following child elements:

  • Chapter
  • Article
  • Selection
  • For
  • If


CRM Documentation - Dynamic Text

CRM Documentation - Dynamic Text Stunnware

Dynamic text is the way to define labels, headings and any other text as a combination of static text and data from the CRM Metadata and CRM customizations. As an example, look at the highlighted line in a sample Table of Contents:

<Chapter
title="Entities
and Attributes"
input="entityList.xml"
output="entityList.htm"
parse="true">
<For
var="@Entity1"
in="EntitiesToProcess"
sortBy="LogicalName"
sortOrder="ascending">
<Chapter title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">
<Chapter
title="Attributes"
input="attributeList.xml"
output="$(@Entity1.LogicalName)\attributes.htm"
parse="true">
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<Article title="$(@Attribute1.LogicalName)"
input="attribute.xml"
output="$(@Entity1.LogicalName)\$(@Attribute1.LogicalName).htm"
parse="true"
/>
</For>
</Chapter>
<If
var="@Entity1"
method="HasEvents">
<Chapter
title="Events"
input="eventList.xml"
output="$(@Entity1.LogicalName)\events.htm"
parse="true">
<For

var="@FormEvent"
in="AllEvents"
of="@Entity1"
sortBy="Name"
sortOrder="ascending">
<Article

title="Form
$(@FormEvent.Name)"

input="formEvent.xml"

output="$(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm"

parse="true"
/>
</For>
<For
var="@Attribute1"
in="AllAttributes"
of="@Entity1"
sortBy="LogicalName"
sortOrder="ascending">
<For
var="@FieldEvent"
in="AllEvents"
of="@Attribute1"
sortBy="Name"
sortOrder="ascending">
<Article title="$(@Attribute1.LogicalName)
$(@FieldEvent.Name)"
input="fieldEvent.xml"
output="$(@Entity1.LogicalName)\events\$(@Attribute1.LogicalName)_$@FieldEvent.UniqueName).htm"
parse="true"
/>
</For>
</For>
</Chapter>
</If>
</Chapter>
</For>
</Chapter>

The element defines an article to be created and sets its title to Form $(@FormEvent.Name). The input file is defined as a static file reference (formEvent.xml), while the output goes to $(@Entity1.LogicalName)\events\$(@FormEvent.UniqueName).htm.

At runtime, most text is evaluated and all occurrences of $(expression) are replaced with the corresponding values. For instance, the green For-Loop operates on all form events found in the current entity. The name of these form events will be OnLoad or OnSave, so Form $(@FormEvent.Name) becomes Form OnLoad or Form OnSave at runtime.

The output filename is evaluated the same way, but has two dynamic parts. Assume that the documentation is currently working on the account entity's OnLoad event, then $(@Entity1.LogicalName) is account. $(@FormEvent.UniqueName) returns a unique event name, which is OnLoad, unless there are multiple OnLoad events defined, in which case they are returned as OnLoad, OnLoad2, OnLoad3 and so on. While this usually doesn't occur in form events, you will notice multiple event handlers for the same events in attributes. Using these replacements, the final output file is account\events\OnLoad.htm.

Note: You don't really care about what's returned in UniqueName. It simply ensures that the help generator has a unique name for each event, which is needed for proper creation of HTML input files and proper references in the Table of Contents.

Dynamic Text with entity variables

Whenever you use dynamic text, the notation is $(@variable.properties). If variable is an entity reference, then properties must evaluate to a valid property of an EntityMetadata object. Please consult the Microsoft CRM 4.0 SDK documentation for a list of properties.

Some examples:

$(@entity1.LogicalName): returns the value of the LogicalName property of the EntityMetadata object referenced in the entity1 variable.

$(@entity1.Description.UserLocLabel.Label): returns the description of the EntityMetadata object referenced in the entity1 variable.

Note: the returned string depends on your CRM language settings. If you have set your CRM language to English, then the localized label will be English as well. If your language is set to German, then you get a German label. If there is no translation for a metadata resource in your language, CRM uses the system's base language.

Dynamic Text with attribute variables

This is identical to using dynamic text with entity variables. However, you are not operating on an EntityMetadata instance but an AttributeMetadata object. Please consult the Microsoft CRM 4.0 SDK documentation for a list of properties available in the AttributeMetadata class.

Dynamic Text with events

Events are extracted from the CRM customizations rather than the CRM Metadata. There's no pre-defined object model you can use, so please use the following documentation for a list of properties you can use when accessing an event variable:

  • Name: returns the event name, like OnSave, OnLoad or OnChange.

  • Enabled: returns true, if the event is enabled, otherwise false.

  • Code: returns the script code.

  • UniqueName: returns a unique event name, which may be the Name itself or the Name plus an index (OnChange, OnChange1, OnChange2 for instance).

  • FormattedHtmlCode: returns the Code in a formatted way to provide better readability in the generated HTML files.


CRM Documentation - Template Files

CRM Documentation - Template Files Stunnware

Template files define the HTML used in your help file. All articles and optionally chapters listed in the Table of Contents reference HTML output files. While these files could be static content, they usually refer to an HTML template in the input folder and use Dynamic Text, For-Loops and If-Expressions to add information from the CRM Metadata or CRM customizations.

Here is a simple example of such a template file:

<?xml version="1.0" encoding="utf-8" ?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" />
<link href="help.css" rel="stylesheet" type="text/css" />
<title>Entity List</title>
</head>
<body>
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
<param name="Keyword" value="Entity List" />
</object>
<div id="mainSection">
<div id="mainBody">
<p>
<h1 class="heading">Entity List</h1>
<div class="summary">
<p>The Entity List contains a short summary of all documented types in your organization.</p>
</div>
</p>
<div id="propertyTableSection" class="section" name="collapseableSection" style="">
<table id="memberList" class="members" frame="lhs" cellpadding="2">
<tr>
<th class="iconColumn"></th>
<th class="nameColumn">Logical Name</th>
<th class="nameColumn">Display Name</th>
<th class="descriptionColumn">Description</th>
</tr>
<For var="@Entity" in="EntitiesToProcess" sortBy="LogicalName" sortOrder="ascending">
<tr data="protected;inherited;">
<td>
<img src="images/entity.gif" alt="Entity" />
</td>
<td>
<a href="$(@Entity.LogicalName)\entity.htm">$(@Entity.LogicalName)</a>
</td>
<td>$(@Entity.DisplayName.UserLocLabel.Label)</td>
<td>$(@Entity.Description.UserLocLabel.Label)</td>
</tr>
</For>
</table>
<a href="#mainBody">Top</a>
</div>
</div>
</div>
</body>
</html>

Note: A template file must be valid XML and the root node is assumed to be the start of an HTML document. When designing pages in an HTML editor, make sure to use XHTML, otherwise your page source may be incompatible and you need to change it manually later.

While the above XML looks pretty much like an HTML page, it also contains the same elements you know from the Table of Contents file. There is a For-Loop referencing the EntitiesToProcess selection. Though the selection is defined in the Table of Contents file, it is available in a template as well. You also see dynamic text, which is replaced with values of the @Entity variable. The output is a table of all entities included in the help file, showing their names and descriptions and also proving a link to each entity:

Note: When creating links to generated pages, you must ensure that they match the output definitions in the TOC. For instance, the link <a href="$(@Entity.LogicalName)\entity.htm">$(@Entity.LogicalName)</a> matches the following line in the TOC:

<Chapter
title="$(@Entity1.LogicalName)"
input="entity.xml"
output="$(@Entity1.LogicalName)\entity.htm"
parse="true">

Automatic Index Creation

To include a good index into your help file, that people can use to search for specific topics, you must add an object as shown in the yellow highlighted area.

<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
<param name="Keyword" value="Entity List" />
</object>

In the sample above, the generated HTML file will be added into the help index, showing a name of Entity List. While in this example it makes sense to provide a static text - because there is only one Entity List in the help file - you will use Dynamic Text in entity-, attribute- and event-specific templates. For instance, the following is taken from an entity template file:

<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
<param name="Keyword" value="$(@Entity1.LogicalName)" />
</object>

Sample files

You find a complete set of template files in the installation directory, which will be similar to C:\Program Files\Stunnware\Stunnware Tools for Microsoft Dynamics CRM 4.0\Templates\Help Generator\MSDN. This folder contains the following files:

  • Attribute.xml: A template used to document an attribute retrieved from the CRM Metadata.
  • AttributeList.xml: A template used to create an attribute list, containing all attributes of an entity with appropriate links to the attribute help topics generated with the Attribute.xml template.
  • Entity.xml: A template used to document an entity retrieved from the CRM Metadata.
  • EntityList.xml: A template used to create an entity list, containing all entities of the CRM organization, with appropriate links to the entity help topics generated with the Entity.xml template.
  • EventList.xml: A template used to create an event list, containing all events of a CRM form, with appropriate links to the event help topics generated with the FieldEvent.xml and FormEvent.xml templates.
  • FieldEvent.xml: A template used to create documentation for a field event (OnChange and others)
  • FormEvent.xml: A template used to create documentation for a form event (OnLoad, OnSave)

Note: Instead of changing these templates files directly, it is recommended to copy the entire folder to a different location and point your documentation to it. You can then change the copied files and still have a backup in place.


FetchXml Wizard - Introduction

FetchXml Wizard - Introduction Stunnware

The FetchXml Wizard is a graphical query editor based on the FetchXml query language. Like a designer in Visual Studio, you can create a query either in a designer window or in a code window. You can also execute queries and look at the result XML. The Stunnware Tools Professional Edition contains additional features that are not available in the Community Edition.

Features (Community Edition)

The Community Edition contains all features that you know from the beginning. It even was enhanced as it now creates code for each .NET language available on your system, while previous versions were limited to C# and VB.NET. I doubt that many of you are using C++, J# or anything else, but it is possible.

For more information about the features available in the Community Edition, click one of the links below.

  • The designer window
  • Parsing an existing FetchXml query
  • Executing a query
  • Converting a FetchXml query to a QueryExpression in any .NET language

Features (Professional Edition)

For more information about the additional features of the Professional Edition, click one of the links below.

  • Compile and execute the generated .NET code
  • Investigate the sent and received SOAP messages
  • Create JavaScript code for use in CRM forms

Related information

  • Software Activation

  • Enabling Extension Modules


FetchXml Wizard - Query Designer

FetchXml Wizard - Query Designer Stunnware

The Query Designer lets you define a FetchXml query without having to know about the XML syntax. To create a new query, click on the New Query toolbar button:

A new Fetch XML Query window is displayed.

To create and edit a query, you always right-click into the designer window or right-click a node. When starting a new query, the designer window is empty and the first thing you have to do is selecting the entity you want to retrieve data from. Right-click anywhere on the designer window to show a context menu of available commands:

See Selecting the main entity for details.

Other settings

The Page Count dropdown defines how many records you want to return. You can select a value from the list or type in any positive value. If you don't want to limit the results, simply delete the value from the edit box.

The Aggregate checkbox is always disabled and serves as an indicator whether you are returning data or the result of an aggregate. The only supported aggregate in FetchXml is Count. You can specify this option when selecting attributes and if you do so, the Aggregate checkbox is checked.

Returning Distinct Values is sometimes needed to prevent duplicates from being returned. You only need to care about it when working with linked entities though. If the result XML contains duplicates, then activating the Distinct Values option usually solves the problem.

XML View

You can switch to the Fetch XML tab at any time to see the query definition. Whenever you change the query in the designer, the XML view is updated as well.


FetchXml Wizard - Selecting the main entity

FetchXml Wizard - Selecting the main entity Stunnware

Each query starts with the definition of the main entity. Right-click anywhere on the designer window to show a context menu of available commands:

Click on Add Main Entity to select the entity from an entity selection dialog:

The entity selection dialog lists all available entities of the connected CRM organization. Select the one you want to access and click OK. I'm using the account entity as an example.

To specify which attributes to return and which conditions to use, right-click the account node:

Main Entity Context Menu

Your context menu may look different, depending on what extension modules you have enabled. For more information about the available commands, please click the links below:

  • Selecting attributes
  • Adding filters and conditions
  • Setting the sort order of the returned data
  • Adding linked entities

The Delete command removes the node and all child nodes. Start Fetch XML Query opens a new Fetch XML Query window and uses the selected entity as a starting point. Show Entity Details was added from the Metadata Viewer extension and opens an entity metadata viewer for the selected entity.


FetchXml Wizard - Selecting Attributes

FetchXml Wizard - Selecting Attributes Stunnware

FetchXml allows to return attributes from the main entity and from linked entities. To specify which attributes to return, right click an entity node and select the Select Attributes command.

There are three options at the top of the attribute picker:

  • Return all attributes: The query requests all attributes. This is a good setting when testing a query, but should be avoided in the final code because of performance implications.
  • Specify the attributes to retrieve: Lets you select the required attributes from the attribute list.
  • COUNT(*): Returns the number of all records the query finds. No attributes are returned. This option corresponds to the Count aggregate function.
  • COUNT(Attribute, Distinct): Returns the number of all records having a value in the specified attribute. No attributes are returned. If the Distinct Values option is activated, only distinct records are counted. This option corresponds to the CountColumn aggregate function.

Note: If you have specified attributes in the attribute list and switch to the Return all attributes or Return the number of records instead of attributes option, the attributes will still be selected. This allows you to switch between modes, without having to re-select the attributes every time.

Depending on your selection, you will see one of the following results in the designer window:

All Attributes

A single attribute node is shown with the text All Attributes.

Counting the number of records

A single attribute node is shown with the text Count Aggregate.

If you have selected the COUNT(Attribute, Distinct) function, the text displayed is CountColumn Aggregate instead.

Selected attributes

One attribute node is shown for each selected attribute. The node text contains the logical name and the display name.

Changing the attribute selection

To change the attribute selection, simply double-click an attribute node. You can also select an attribute node and press the delete key to remove it from the selection.


FetchXml Wizard - Adding Filters and Conditions

FetchXml Wizard - Adding Filters and Conditions Stunnware

The most important query parts are filters and conditions. A filter describes whether all conditions in a condition set must be true (AND filter) or at least one (OR filter). Filters can contain sub-filters and each filter contains one or more conditions. To create a filter, right click an entity node and select the Add Filter command.

You always have to create a filter before adding conditions and the AND-Filter is the default filter type. Select OK to add the filter to your query.

Adding conditions

To add conditions to the filter, right-click the filter node and select Add Condition from the context-menu.

In the condition dialog select an attribute from the attribute dropdown. The condition dropdown shows all condition operators available for the selected attribute. Some operators do not require an argument, like a check for a null value. Some operators, like In the last X days, require exactly one parameter and others require two or more. The Value text box accepts one or more parameters based on the selected condition operator. If no parameter is required, it is disabled. If two or more parameters are needed (or valid), then enter each parameter on a separate line:

If the selected attribute is a picklist, you can select the values by clicking the Pick button:

Note: The data you enter in the Value field is evaluated. For instance, if you have to enter a unique id (GUID), then you have to enter a valid GUID, otherwise the data is rejected.

Adding Sub-Filters

To add sub-filters to a filter, right-click the filter node and select Add Filter from the context-menu.

Editing filters and conditions

To edit a filter or condition, double-click the node. The appropriate dialog appears allowing to change the settings.

Deleting filters and conditions

There are two ways to delete a filter or a condition. Either right-click the node and select the Delete command from the context menu or select the node and press the delete key.

Note: Deleting a filter also deletes any contained sub-filters and conditions.


FetchXml Wizard - Setting the sort order

FetchXml Wizard - Setting the sort order Stunnware

You usually want the data returned by a query to be ordered. To specify the sort order, right click an entity node and select the Set Sort Order command.

Though FetchXml allows more sort orders, the dialog is limited to five sort fields. In the example above, the returned data is sorted by country first. Records with the same country are sorted descending by creation date. If you need more than five sort orders, you have to specify them in the Fetch XML window.


FetchXml Wizard - Adding linked entities

FetchXml Wizard - Adding linked entities Stunnware

Linked entities are used to return data from more than one entity or to define a JOIN command. To specify a linked entity, right click an entity node and select the Add Linked Entity command.

Add Linked Entity

The Use existing relationship list shows all available entity relationships. As an example, we want to return additional data from the user who created the entity:

Link from account to systemuser

The text displayed for the relationship shows the source and target entity and attribute. In the example above it means that you are linking the systemuser entity to the account entity. The appropriate systemuser entity is identified by the condition systemuser.systemuserid = account.createdby.

You can select 1:many and many:many relationships in the same way, but a many:1 relationship is the most common one. These relationships represent lookup, owner or customer fields on the selected entity, though they don't have to present on the CRM form.

Specifying the relationship manually

While using an existing relationship should fit your needs most of the time, you are not limited to using it. As an example, you can create the following relationship yourself:

It is a link from the account to the contact entity and it adds a condition based on the account's and contact's country. This relationship doesn't exist, but you can use it in FetchXML.

Linked Entities in the designer window

A linked entity is shown in italics:

Linked entity in the designer window

You can edit the relationship by double-clicking it and you have the same context-menu as for the main entity.

Note: You can change the relationship later on, but be aware that doing so may invalidate the child definitions. For instance, if you change a relationship that was pointing to the systemuser to a relationship targeting the contact entity, then attribute definitions and conditions may no longer work.


FetchXml Wizard - FetchXml View

FetchXml Wizard - FetchXml View Stunnware

Besides the query designer window, you can manage the XML query directly. The designer usually is the fastest way to create and test a new query, but the XML view is faster when making smaller changes. However, you have to click the Parse button after making changes to the XML code to synchronize the designer.

The XML view also is the easiest way to edit an existing query. Simply paste a query into the XML editor and click the Parse button. As an example, you can use the following query:

<fetch mapping="logical">
<entity name="account">
<attribute name="address1_city" />
<attribute name="address1_country" />
<attribute name="name" />
<order attribute="address1_country" />
<order attribute="name" />
<filter>
<condition attribute="address1_country" operator="not-null" />
</filter>
</entity>
</fetch>

Copy the above XML and paste it into the query window:

Parsing a query

Now click the Parse button and the entire query is parsed. This process may need to access the metadata, so don't blame the application if it needs some seconds to complete. When finished, the parsed query is shown in the designer window:


FetchXml Wizard - Executing a query

FetchXml Wizard - Executing a query Stunnware

When you are done with the query definition or you want to try what you have done so far, simply press the Execute button in the toolbar:

The query is executed and the result XML is displayed in the Result XML tab:

Error Messages

If an exception is thrown while executing the query, the exception message is displayed in the Output window at the bottom:


FetchXml Wizard - Converting a query to the QueryExpression syntax

FetchXml Wizard - Converting a query to the QueryExpression syntax Stunnware

Using a FetchXml query in code is much easier than writing a full-blown query using the QueryExpression syntax. However, the disadvantage of FetchXml is that you have to parse the result yourself. A RetrieveMultiple request returns a collection of BusinessEntity objects, which are easier to use than an XML string. If you use the Code Generator extension it will become even easier.

The FetchXml wizard provides a tool to convert your FetchXml query into a QueryExpression. There is a FetchXmlToQueryExpression request, but it fails if the FetchXml query contains features that are not supported in a QueryExpression. Furthermore, the FetchXmlToQueryExpression request only returns a QueryExpression object, but not the required code to create it.

Converting the query to the QueryExpression syntax (Web Service and CRM SDK)

Switch to the QueryExpression (Web Service) tab and select your favorite .NET language in the Language dropdown.

Convert to .NET Code

As soon as you pick a language, the code is displayed in the editor window:

Generated C# Code

The tool should find any .NET language on your system. On a typical developer machine it should include C#, VB.NET, J# and C++. If you have other languages installed, they will be available as well.

Note: The code shown on the QueryExpression (Web Service) tab is meant to be used with a CrmService object of a CRM web reference. When working with the CRM SDK assemblies please use the code from the QueryExpression (CRM SDK) tab.

How to use the code

The generated code uses internal classes and interfaces to allow it to be run. You shouldn't care that much about the implementation details. Instead, simply copy the query code to your Visual Studio project and you should be fine. Here's a sample output:

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.3053
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Stunnware.Crm4.Query {
    using Stunnware.Crm4.App.Framework.FetchXmlWizard;
    using System;
    using System.Web.Services;
    using System.ComponentModel;
    using Stunnware.Crm4.CrmService4;

    /// <summary>
    /// Sample class showing the use of a QueryExpression.
    /// </summary>
    public class Sample : object, IWebServiceQueryExpression {

        /// <summary>
        /// The original FetchXML query.
        /// </summary>
        const String fetchXml = @"<fetch mapping=""logical""><entity name=""account""><attribute name=""address1_city"" /><attribute name=""address1_country"" /><attribute name=""name"" /><order attribute=""address1_country"" /><order attribute=""name"" /><filter><condition attribute=""address1_country"" operator=""not-null"" /></filter></entity></fetch>";

        /// <summary>
        /// Executes a query and returns the matching records.
        /// </summary>
        /// <param name="crmService">A CrmService object (Web Service Reference, not from the SDK assemblies).</param>
        /// <returns>A BusinessEntityCollection holding the result.</returns>
        public virtual BusinessEntityCollection Execute(CrmService crmService) {

            QueryExpression query = new QueryExpression();

            // Setup the query for the account entity
            query.EntityName = "account";

            // Specify the columns to retrieve
            ColumnSet columns = new ColumnSet();
            columns.Attributes = new String[] {
                "address1_city",
                "address1_country",
                "name"};

            query.ColumnSet = columns;
            query.Criteria = new FilterExpression();
            query.Criteria.FilterOperator = LogicalOperator.And;

            // Create the address1_country condition
            ConditionExpression condition1 = new ConditionExpression();
            condition1.AttributeName = "address1_country";
            condition1.Operator = ConditionOperator.NotNull;

            query.Criteria.Conditions = new ConditionExpression[] {
                condition1};

            OrderExpression order1 = new OrderExpression();
            order1.AttributeName = "address1_country";
            order1.OrderType = OrderType.Ascending;

            OrderExpression order2 = new OrderExpression();
            order2.AttributeName = "name";
            order2.OrderType = OrderType.Ascending;

            query.Orders = new OrderExpression[] {
                order1,
                order2};

            // Execute the query and return the result
            return crmService.RetrieveMultiple(query);
        }
    }
}

The highlighted code contains the original FetchXml query and the code for your application. Everything else is created to run the code.


FetchXml Wizard - Compiling and executing the .NET code

FetchXml Wizard - Compiling and executing the .NET code Stunnware

If you are running the Professional Edition, you can even run the code to verify it's working. After you have generated the code, click the Run .NET Code button:

Run .NET Code

The .NET code is compiled and executed. If the compiler finds an error, the code is not executed and the Compiler Messages tab contains errors and warnings like you see them in Visual Studio. Otherwise you see a successful output like the following:

Knowing that the code is correct is one thing. However, there's even more: investigating the SOAP messages and generating JScript code to use in CRM forms!

Note: Compiling and executing the .NET code is only available in the Professional Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules

  • SOAP Messages

  • JScript Code


FetchXml Wizard - SOAP Messages

FetchXml Wizard - SOAP Messages Stunnware

If you are running the Professional Edition, you can look at the SOAP messages being sent and received after you have run the generated .NET code. Switch to the SOAP Messages tab at the bottom:

You see a request and a response message. The request contains the query and the response contains the result. When clicking on a message, the SOAP message tab at the top is opened and the SOAP message is displayed:

To see the response message, simply click on it in the SOAP Messages list:

Note: SOAP messages are only available in the Professional Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules

  • JScript Code


FetchXml Wizard - JScript for CRM forms

FetchXml Wizard - JScript for CRM forms Stunnware

If you are running the Professional Edition, you can generate the JScript code you need to run the same QueryExpression you did from .NET. After you have run the generated .NET code, switch to the SOAP Messages tab at the bottom:

Click on the request message and wait for the SOAP message to be displayed:

Now switch to the JScript Code tab to see the CRM form script:

It's still your responsibility to parse the result, but you don't need to worry about the query.

Note: JScript code is only available in the Professional Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules


Customization Comparer - Introduction

Customization Comparer - Introduction Stunnware

If you have to troubleshoot a CRM installation, it's very important to know if the system has changed and what changes have been made since the last time you deployed your solution. Many problems are based on customization changes, but finding the differences between the current and a previous system state is very difficult and time-consuming.

The Customization Comparer takes two CRM customization export files (customization.xml) and compares their contents. All modifications are shown in a result tree, giving a quick view of what has changed. All you have to do is exporting all customizations and save the file for later reference. You can then, at any time, do an export again and compare these files. You can also export a subset of customizations instead.

Note: The Customization Comparer module requires the Professional Edition to be fully functional. It's limited to accounts and contacts in the Community Edition.

For more information, click one of the links below:

  • Software Activation

  • Enabling Extension Modules

  • Comparing Customization Files


Customization Comparer - Comparing Customization Files

Customization Comparer - Comparing Customization Files Stunnware

To compare two customization files, click the Compare Customization Files button on the Tools page:

The Old File points to an export file created in the past and the New File points to the export file containing the current customizations. That's all you need to compare, but sometimes it's helpful to limit the result, which you do by specifying options.

When activating Ignore Labels, different labels are not shown in the result. Specifying one ore more values in Only these LCIDs ignores any label with a different locale identifier. You will find this extremely helpful if additional languages were enabled or existing languages were disabled. Multiple locale identifiers are separated with commas.

Ignore Object Type Codes should be self-explanatory: when exporting customizations from a source system and importing these customizations on a target system, the assigned object type codes may differ. Activating this option will ignore different object type codes.

To start the comparison, click the Compare button.

A typical export file will take between 5 and 15 seconds to compare. If your customization files do contain a lot of data, it can take considerably longer though. When finished, the Results tab is activated and you see the modifications:

In the above sample output, you see that the size of the Sw_name attribute was changed from 100 to 160 and a new attribute named Sw_NewAttribute was added. Furthermore, the sw_newattribute was added to the form and replaced an empty cell. Finally, two privileges were added to the Sales Manager role.

Modifications are yellow, new items are green and deleted items are shown in red color. To see the differences in more detail, just double click an item:

Note that the displayed XML doesn't entirely match the definition in the customization file. The name of the root node (Attribute in the above) usually is different, but the contents are the same.

The left pane displays the XML of the old export file and the right pane displays the XML of the current export file. This layout is best suited to compare the files line by line, but you have to scroll horizontally to view entire lines. However, you can click Switch Split Mode to get an alternate display:

You can change the displayed XML, but these changes are not persisted. It's an easy way to add comments before printing though.


Trace File Viewer - Introduction

Trace File Viewer - Introduction Stunnware

Sometimes weird things happen in Microsoft CRM and the error messages provided are not always helpful. The good news is that CRM provides a powerful logging mechanism, called CRM tracing. To enable tracing, please refer to the appropriate Microsoft KB Article.

The bad thing about these trace files are that they are hard to read and analyze. If you don't know what exactly to look for, then it can be a very time-consuming process. The Trace File Viewer allows easy parsing of such files and offers a variety of filtering options.

Note: Stunnware has made available a Trace File Viewer since early 2006 and the initial release can still be found on Michael Höhne's CRM Blog. It is a free extension and doesn't require a subscription to be used.

For more information, click one of the links below:

  • Enabling Extension Modules

  • Analyzing Trace Files


Trace File Viewer - Analyzing Trace Files

Trace File Viewer - Analyzing Trace Files Stunnware

To analyze a trace file, select the Open command from the Trace Files main menu:

Open Trace File

Select the file to analyze and click the Open button. Depending on the file size, it will take a few seconds (5MB) up to a minute (100MB) or longer to open and parse and display the file:

You can filter the displayed data by any displayed value. Just hover over the column headers and click the small filter symbol:

A dropdown appears, containing all available values:

After selecting a value, the list only displays the entries matching the filter. The current filter criteria is shown at the bottom:

You can apply additional filters or do a free search by clicking the Edit Filter button. If you want to view the original entry, simply double-click a row:


ISV Config and Sitemap Editor - Introduction

ISV Config and Sitemap Editor - Introduction Stunnware

When making changes to the ISV.Config or sitemap, you usually follow these steps:

  1. Export the ISV.Config or sitemap from CRM and saving the customation zip file to your disk.

  2. Extracting the customization.xml inside the zip file to your disk.

  3. Starting an editor like Notepad or Visual Studio to edit the customization file.

  4. Import the customization file.

  5. Cross your fingers that that you haven't made an error.

Even though ISV.Config and sitemap changes are not a daily business, the above is a time consuming process, especially when the results do not match your expectations, in which case you repeat step 3 and 4 (and probably 5, though this doesn't cost too much time).

The ISV.Config editor and the Sitemap editor allow you to easily load the customizations from CRM, edit the XML in an XML editor and validate the XML. You may still cross your fingers when saving your changes, but at least you're prevented from saving invalid definitions.

Note: The ISV Config Editor and the Sitemap Editor are free extensions. You do not need a subscription to use them. These editors are part of the Customization plug-in (named Customization Diff Tool in the module list).

For more information, click one of the links below:

  • Enabling Extension Modules

  • The ISV.Config Editor

  • The Sitemap Editor


ISV Config Editor

ISV Config Editor Stunnware

To load the ISV.Config from the CRM server, select the Tools page and click Edit ISV Config:

You can directly edit the XML and validate your input at any time by pressing the Verify button. The verification process uses the /schemas/isv.config.xsd schema to validate the XML. This automatically happens when uploading the XML to prevent an invalid ISV.Config on the server. Uploading is done by clicking the Upload button.


Sitemap Editor

Sitemap Editor Stunnware

To load the Sitemap from the CRM server, select the Tools page and click Edit Sitemap:

You can directly edit the XML and validate your input at any time by pressing the Verify button. The verification process uses the /schemas/sitemap.xsd schema to validate the XML. This automatically happens when uploading the XML to prevent an invalid sitemap on the server. Uploading is done by clicking the Upload button.