Workflows as Entities

It probably won’t surprise you to learn that Microsoft Dynamics CRM stores workflow definitions in entities, just like most things in Microsoft Dynamics CRM. Conveniently, this allows developers to access and manipulate workflows through the familiar CrmService API.

The workflow Entity

The entity that contains most of the workflow definition is appropriately named workflow. Table 12-1 lists the attributes of the workflow entity.

Table 12-1. Attributes of the workflow Entity

name

Type

Description

activeworkflowid

Lookup

Only populated if the workflow has a type equal to Definition and a statecode of Published. Contains the workflowid for the compiled workflow that is executed when this workflow is triggered. See "Workflow Publication" later in this chapter for more information.

activities

String

Contains the declarative workflow definition in Extensible Application Markup Language (XAML). For workflows defined in the CRM workflow designer, this attribute is only populated after a workflow is published and only for the workflows with a type equal to Activation. See "Declarative Workflows" later in this chapter for more information.

createdby

Lookup

The systemuser that created the workflow.

createdon

CrmDateTime

The date and time the workflow was created.

description

String

The description of the workflow definition.

iscrmuiworkflow

CrmBoolean

True if the workflow was defined in the Microsoft Dynamics CRM 4.0 workflow designer; otherwise false.

modifiedby

Lookup

The systemuser that last modified the workflow definition.

modifiedon

CrmDateTime

The date and time the workflow was last modified.

name

String

The name of the workflow.

ondemand

CrmBoolean

True if this workflow is allowed to be executed on demand by users; otherwise false.

ownerid

Owner

The owner of the workflow.

owningbusinessunit

Lookup

The workflow owner’s business unit.

parentworkflowid

Lookup

If the workflow has a type of Activation, parentworkflowid references the workflow that represents the definition.

plugintypeid

Lookup

References the plugintype for a compiled workflow. Only populated for workflows with a type of Activation. See "Workflow Publication" later in this chapter for more information.

primaryentity

EntityNameReference

A reference to the type of the primary entity for the workflow definition.

rules

String

Contains the declarative workflow’s policy rules in XAML. For workflows defined in the CRM workflow designer, this is only populated after a workflow is published and only for the workflows with a type equal to Activation. See "Declarative Workflows" later in this chapter for more information.

scope

Picklist

The scope of the event that automatically triggers the workflow. Valid values are exposed as constant integer fields from the WorkflowScope class (User = 1, BusinessUnit = 2, Deep = 3, Global = 4). For example, if scope is set to WorkflowScope.User, the workflow only automatically executes if the primary entity is also owned by the workflow owner. See "Automatic Workflows" in Chapter 6 for more information.

statecode

WorkflowStateInfo

The state of the workflow. Valid values are exposed as constant integer fields from the WorkflowState class. (Draft = 0, Published = 1).

statuscode

Status

Additional information about the state of the workflow. Currently, each statecode only has a single valid value for statuscode (Draft = 1, Published = 2).

subprocess

CrmBoolean

Indicates whether the workflow can be included in other workflows as a child process.

type

Picklist

Used to determine the type of the workflow. Valid values are exposed as constant integer fields from the WorkflowType class (Definition = 1, Activation = 2, Template = 3). A workflow with type equal to Activation indicates that it has been compiled from a definition during publication. See "Workflow Publication" later in this chapter for more information.

uidata

String

When a workflow is defined in the Microsoft Dynamics CRM workflow designer (iscrmuiworkflow equals true), uidata contains proprietary information about the configuration of the steps and stages.

workflowid

Key

The primary key for the workflow.

If you have read Chapter 6, many of these attributes, such as scope and ondemand, are undoubtedly familiar to you because you worked directly with them in the Microsoft Dynamics CRM workflow designer. Others, such as activities, activeworkflowid, and rules, are not as obvious, and for that reason we examine them more closely later in this chapter.

Interacting with Workflows Through CrmService

Because Microsoft Dynamics CRM stores workflows within entities, you can access and manipulate them using the familiar CrmService methods. For example, ProgrammingWith-DynamicsCrm4.WorkflowManager uses the code from Example 12-1 whenever it needs to refresh the list of workflows.

Example 12-1. WorkflowLogic’s RetrieveWorkflows method

public IEnumerable<workflow> RetrieveWorkflows(params string[] attributes)
{
    QueryExpression query = new QueryExpression();
    query.EntityName = "workflow";
    ColumnSet cols = new ColumnSet();
    cols.AddColumns(attributes);
    query.ColumnSet = cols;
    query.Criteria.AddCondition(
        "type", ConditionOperator.Equal, WorkflowType.Definition);

    BusinessEntityCollection results = this.CrmService.RetrieveMultiple(query);
    foreach (workflow w in results.BusinessEntities)
    {
        yield return w;
    }
}

This query returns all workflow definitions in the system, regardless of their state or owner. We use the results of this method to populate the ListView control in the main form of the ProgrammingWithDynamicsCrm4.workflowManager tool.

In addition to workflow retrieval and deletion, you can use the CrmService API for all of the other manipulations such as updating, deleting, and reassigning workflow entities to new owners. See Chapter 3, for more information on how to use the API to execute this functionality.

Workflow Publication

Once you begin managing workflows through the API, you will quickly find yourself needing to publish and unpublish workflows programmatically. Example 12-2 demonstrates how easily you can accomplish this with the SetStateworkflowRequest.

Example 12-2. WorkflowLogic’s PublishWorkflow and UnpublishWorkflow methods

const int WorkflowStatusDraft = 1;
const int WorkflowStatusPublished = 2;

public void PublishWorkflow(Guid workflowId)
{
    SetStateWorkflowRequest publishRequest = new SetStateWorkflowRequest();
    publishRequest.EntityId = workflowId;
    publishRequest.WorkflowState = WorkflowState.Published;
    publishRequest.WorkflowStatus = WorkflowStatusPublished;

    this.CrmService.Execute(publishRequest);
}

public void UnpublishWorkflow(Guid workflowId)
{
    SetStateWorkflowRequest unpublishRequest = new SetStateWorkflowRequest();
    unpublishRequest.EntityId = workflowId;
    unpublishRequest.WorkflowState = WorkflowState.Draft;
    unpublishRequest.WorkflowStatus = WorkflowStatusDraft;

    this.CrmService.Execute(unpublishRequest);
}

Best Practices

Best Practices

Notice that the WorkflowStatusPublished and WorkflowStatusDraft constants are defined locally in the WorkflowLogic class. Although the CRM SDK provides the WorkflowState class to access the statecode definitions, it does not provide a similar class for statuscode. To make your code more maintainable, it is a good idea to define some constants of your own to represent the values.

Although the two methods in Example 12-2 are fairly straightforward, behind the scenes CRM is doing more than simply changing some attribute values in response to these calls.

Back in Example 12-1, you saw that we added a condition to make sure we only retrieve workflows if the type equals WorkflowType.Definition. Without this condition, the CrmService appears to return duplicate workflow definitions to our ListView. In reality, a compiled copy of a workflow definition is created each time you publish a workflow. The compiled version is marked with type set to WorkflowType.Activation and the activeworkflowid attribute on the definition workflow is updated to reference this compiled copy.

Compilation takes the stages and steps you defined in the workflow designer out of the ui-data attribute and converts them into XAML. We’ll take a closer look at XAML in the section "Declarative Workflows" later in this chapter, but for now just understand that the XAML is XML that you use to describe the stages and steps.

XAML is combined with some generated code and compiled into a class in a new assembly. The new assembly and class are stored in a pluginassembly entity and a plugintype entity respectively. The resulting plugintype is associated with the compiled workflow through the workflow’s plugintypeid attribute.

In addition to compiling the workflow, a series of related entities of type workflowdependency are created during publication. These entities contain additional information about when to execute a workflow instance and what data it requires during execution. Because this is a vital and yet complex part of workflow execution, we discuss the workflowdependency entity in more depth in the next section.

The publication process enables Microsoft Dynamics CRM to streamline the execution of workflow instances by optimizing the workflow into a .NET assembly and preparing additional data to dictate how and when to execute it.

The workflowdependency Entity

As mentioned in the previous section, a series of workflowdependency entities are created during publication to instruct CRM both when a workflow should be executed and what data it needs during execution. A workflowdependency can be one of eight different types. You can use the type attribute to determine the type of the workflowdependency. The valid values for type can be found as constant integer values in the WorkflowDependencyType class, as shown in Table 12-2.

Table 12-2. WorkflowDependencyType Field Values

Field

Value

Description

Attributedefinition

8

Creates a dependency on a custom attribute. A custom attribute cannot be deleted if a published workflow references it with this dependency.

CustomEntitydefinition

7

Creates a dependency on a custom entity. A custom entity cannot be deleted if a published workflow references it with this dependency.

LocalParameter

2

Used to define local parameters that exist as properties on the compiled workflow class. These properties are frequently modified and read by PolicyActivity instances as defined in the workflow’s rules attribute.

PrimaryEntityImage

3

Specifies which attributes of the primary entity should be passed in to the workflow instance.

PrimaryEntityPostImage

5

Specifies which attributes of the primary entity’s post image should be passed in to the workflow instance.

PrimaryEntityPreImage

4

Specifies which attributes of the primary entity’s pre image should be passed in to the workflow instance.

RelatedEntityImage

6

Specifies the attributes needed by this workflow from an entity directly related to the primary entity.

SdkAssociation

1

This dependency is used to define which SDK messages should cause the related workflow to execute.

With these dependency types in hand, we can take a look at the other attributes exposed from the workflowdependency entity. Table 12-3 lists all of the workflowdependency attributes and their uses.

Table 12-3. The workflowdependency Entity

property

Type

Description

createdby

Lookup

The user that created the workflowdependency.

createdon

CrmDateTime

The date and time the workflowdependency was created.

customentityname

String

If type is CustomEntitydefinition, this is the name of the custom entity the workflow is dependent upon.

dependentattribute-name

String

If type is Attributedefinition, dependentattributename is the name of the attribute that is required.

dependententityname

String

If type is Attributedefinition, dependententityname is the name of the entity that the required attribute must exist on.

entityattributes

String

The entityattributes property has multiple meanings depending on the type attribute. Regardless of the meaning, it always contains a comma-separated list of attribute names. If type is SdkAssociation and sdkmessageid references the Update message, entityattributes contains the names of the attributes that automatically trigger the workflow. For any of the entity image defining types, entityattributes contains the list of attributes that should be populated in the image.

modifiedby

Lookup

The user that last modified the workflowdependency.

modifiedon

CrmDateTime

The date and time the workflowdependency was last modified.

owningbusinessunit

UniqueIdentifier

The business unit that owns the workflowdependency.

owninguser

UniqueIdentifier

The user that owns the workflowdependency.

parametername

String

This identifies the name of a property that will be defined on the compiled workflow instance. These properties can be accessed from rules used by PolicyActivity instances.

parametertype

String

Only populated when type is set to LocalParameter, parametertype contains the name of the .NET type for the local property that is defined on the workflow.

relatedattributename

String

When type is set to RelatedEntityImage, the relatedattributename property is set to the name of the attribute on the primary entity that contains the related entity.

relatedentityname

String

When type is set to RelatedEntityImage, the relatedentityname property is set to the name of the related entity type.

sdkmessageid

Lookup

When type is set to SdkAssociation, sdkmessageid is the related message that automatically triggers the workflow execution.

type

Picklist

Determines the type of the workflowdependency. See Table 12-2 for a list of possible values.

workflowdependencyid

Key

The primary ID for the workflowdependency.

workflowid

Lookup

The workflow this dependency is associated with.

Workflow dependencies play an important but subtle role in the Microsoft Dynamics CRM workflow processing. To help understand the complexities of workflow dependencies, we will create a simple workflow through the native workflow designer and then examine the workflow dependencies generated as a result.

Examining workflow dependencies created by the native workflow designer

  1. Using the native workflow designer, create a workflow named Dependency Test that automatically executes when an opportunity is created. (Refer to Chapter 6 if you need a refresher on using the native workflow designer.)

  2. Set the workflow’s scope to Organization.

  3. Add a Check Condition step to check whether the opportunity’s estimated revenue is greater than or equal to $10,000.

  4. Add a Create Record step to create a follow-up phone call if the condition evaluates to true. Set the subject of the phone call to Follow Up For New Opportunity and set the due date to three days after the opportunity’s creation date.

    At this point, your workflow should look like the following image:

    The workflowdependency Entity
  5. Publish the workflow.

  6. Launch the ProgrammingWithDynamicsCrm4.WorkflowManager tool as described earlier in this chapter and connect to your Microsoft Dynamics CRM server.

  7. Select the Dependency Test workflow from the list and click the Show Dependencies button.

  8. You should see the workflow dependencies list in a grid as shown here. Resize the columns and scroll to examine all of the dependency properties.

The workflowdependency Entity

By examining the workflow dependencies we can see that the majority of them have a type of AttributeDefinition (8) that defines attributes that need to exist for the workflow to run. Some of the attributes defined in the list are not directly referenced by anything we specified in our steps, but Microsoft Dynamics CRM uses them behind the scene regardless.

A dependency of type SdkAssociation (1) also dictates the workflow should be run in response to a Create message. If we had selected more messages to automatically trigger the workflow, they would show up as additional dependencies.

Two of the dependencies are used to request that images of the primary entity be passed in as local parameters during the workflow execution. These images allow our workflow to reference attributes off of the primary entity such as estimatedrevenue and createdon without needing to retrieve the data manually.

Note

Note

You may have noticed that the name and opportunityid attributes are also included in the primary entity image. This is because those attributes represent the primary attribute and primary key for the entity and they are always included in the primary entity image, regardless of whether you directly reference them.

The final dependency has a type of LocalParameter (2) and is used to define a local DynamicEntity property on the workflow itself. This property is referenced by PolicyActivity instances to populate and create the phonecall entity.

Retrieving Workflow Dependencies

Before we move on from workflow dependencies, let’s look at how ProgrammingWithDynamicsCrm4.WorkflowManager retrieves the workflow dependencies from the CrmService. Example 12-3 shows the RetrieveWorkflowDependencies method from the WorkflowLogic class.

Example 12-3. The RetrieveWorkflowDependencies method

public IEnumerable<workflowdependency> RetrieveWorkflowDependencies(
    Guid workflowId, params string[] attributes)
{
    QueryExpression query = new QueryExpression();
    query.EntityName = "workflowdependency";
    query.ColumnSet = new ColumnSet(attributes);
    query.Criteria.AddCondition("workflowid", ConditionOperator.Equal, workflowId);

    BusinessEntityCollection results = this.CrmService.RetrieveMultiple(query);
    foreach (workflowdependency dependency in results.BusinessEntities)
    {
        if (dependency.sdkmessageid != null)
        {
            RetrieveRequest request = new RetrieveRequest();
            request.ReturnDynamicEntities = true;
            request.ColumnSet = new ColumnSet(new string[] {"name"});
            request.Target = new TargetRetrieveDynamic()
            {
                EntityId = dependency.sdkmessageid.Value,
                EntityName = "sdkmessage"
            };

            RetrieveResponse response =
                (RetrieveResponse)this.CrmService.Execute(request);

            DynamicEntity message = (DynamicEntity)response.BusinessEntity;

            dependency.sdkmessageid.name = (string)message["name"];
        }

        yield return dependency;
    }
}

Note that the workflowid passed in to this method should be the activeworkflowid attribute of a workflow with a type equal to definition. This is because workflow dependencies are created for the active workflows during publication, and are not tied to the definition itself.

Warning

Warning

Notice that RetrieveWorkflowDependencies has special logic around populating the name property on the sdkmessage attribute. This is done to hide a rare inconsistency with the CrmService RetrieveMultiple message, where the name of a Lookup attribute is not populated. The problem is further compounded if you are referencing the CRM SDK assemblies instead of a Web Reference, because the sdkmessage entity is not deserialized correctly from CrmService. To get around this, you must request that a DynamicEntity be returned.

Now that you have an understanding of workflow dependencies and the tools to explore them more deeply when needed, you are ready to move on to the main topic of the chapter: declarative workflows.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset