HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket


Once a Workflow is defined, you can use it to moderate your application's requests, actions, and resources. Moderating these entities amounts to maintaining a record of the state of each entity within the `Workflow`.

## Represent moderation state

In the Optimizely Community API, a record of an entity's state within a `Workflow` is represented by the `WorkflowItem` class.

An instance of `WorkflowItem` captures several important data points about the state of a `Workflow` entity.

  • The `Workflow` property identifies the Workflow with which the entity is associated.

  • The `State` property identifies the entity's state within the Workflow at this point in time.

  • The `Target` uniquely identifies the entity under moderation. This is a custom identifier, defined within your application. The `Target` is a key that associates a series of `WorkflowItems` to a particular entity under moderation. See _References_ in [Discover the platform](🔗).

A series of `WorkflowItems` with the same `Target` value represents the moderation history for the entity identified by that reference. The most recent `WorkflowItem` in the series represents the current state of the entity.

### Manage entities within a workflow

The table below illustrates the moderation history for three example resources within a `Workflow`.

ID  Workflow State Target Date 
 1 A Pending Resource A 3/1/2022
 2 A Pending  Resource B 3/2/2022
 3 A In Review  Resource A 3/3/2022
 4 A Published  Resource A 3/4/2022
 5 A In Review  Resource B 3/5/2022
 6 A Pending  Resource C 3/6/2022

Each `WorkflowItem` represents a transition within a workflow (in this example, **workflow A**). Each time an entity is moderated within a `Workflow`, a `WorkflowItem` is committed to record its new state. Each `WorkflowItem` represents an individual record in the entity's moderation history.

**Explanation of lines**

  1. Resource A enters moderation. The application adds a `WorkflowItem` with a "Pending" state (the workflow's initial state).

  2. Resource B enters moderation. The application adds a `WorkflowItem` with a "Pending" state.

  3. Resource A transitions to an "In review" state. The application adds a `WorkflowItem` with an "In Review" state.

  4. Resource A transitions to a "Published" state. The application adds a `WorkflowItem` with a "Published" state.

  5. Resource B transitions to an "In review" state. The application adds a `WorkflowItem` with an "In Review" state.

  6. Resource C enters moderation. A `WorkflowItem` is added with a "Pending" state. The application adds a `WorkflowItem` with a "Pending" state.

So, the green background indicates each entity's most recent transition and, therefore, its current workflow state. The table also provides a history. For example, when retrieving `WorkflowItem`s for Resource A, you can follow its history from "Pending" > "In review" > "Published."

## Manage moderation state

In the Optimizely Community API, `WorkflowItem`s are managed through a service that implement the `IWorkflowItemService interface`. The workflow item service provides the ability to persist and retrieve workflows that you define. If your application uses asynchronous programming to improve the overall responsiveness of your application, this service also exposes Async versions of these APIs. The sections below explain, both, the synchronous and asynchronous APIs of the workflow item service. See _Async API_ in [Discover the platform](🔗).

  • Accessing an `IWorkflowItemService`

  • Adding a `WorkflowItem`

  • Retrieving a `WorkflowItem`

  • Removing a `WorkflowItem`

This service provides the ability to persist, retrieve, and remove `WorkflowItems` that you define.

### Access an IWorkflowItemService

If the Moderation feature is installed to an Optimizely CMS site via the site integration package, you can get an instance of this service from the inversion of control (IoC) container.

Example:



If the feature is installed to a non-Optimizely CMS site, you can get an instance of a service from the default `factory` class provided in the package.

Example:



### Add a WorkflowItem

The addition of a `WorkflowItem` records the transition of an entity under moderation to a new state. To add a `WorkflowItem`, use the `Add(WorkflowItem,TransitionSessionToken)` method of `IWorkflowItemService`.

This method accepts:

  • An instance of the `WorkflowItem` class, which describes the new state of the target under moderation.

  • An instance of the `TransitionSessionToken` class, which indicates that exclusive access to transition the target has been successfully obtained. For information on how to obtain a `TransitionSessionToken`, see _Transition Sessions_ in [Moderation workflows](🔗).

The method returns a new instance of `WorkflowItem`, which has been populated with any additional, system-generated data (for example, a unique ID).

The example below illustrates the addition of a `WorkflowItem` to enter a resource into moderation. A `WorkflowItem` is added for the resource with a `Workflow`'s initial state.



For a more comprehensive example of how transition sessions are leveraged, see _Transition Sessions_ in [Moderation workflows](🔗).

In the previous add workflow item example, the request to add a workflow item is invoked synchronously. An example of adding a workflow item asynchronously using the asynchronous overloads of the `BeginTransitionSession` and Add methods is also described in _Transition Sessions_ in [Moderation workflows](🔗).

The following exceptions may occur in the course of using this method:

  • A `WorkflowDoesNotExistException` occurs if the specified `workflow` ID is not found.

  • An `InvalidWorkflowStateException` occurs if the `workflow` item being added has a state that does not exist in the associated `workflow`.

  • A `TransitionSessionDeniedException` occurs if the specified `TransitionSessionToken` is not valid or a different client has already obtained exclusive access to the target of moderation.

Note

While overloads of the `Add` method exist, `Add(WorkflowItem,TransitionSessionToken)` is the recommended approach for implementing the safe transition of a target into a new state. Using this method consistently when implementing moderation strategies helps ensure the integrity of your workflow.

To add a `WorkflowItem`, without regard for any active transition sessions, use the `Add(WorkflowItem)` method of `IWorkflowItemService`.

This method accepts an instance of the `WorkflowItem` class, which describes the new state of the target under moderation.

The method returns a new instance of `WorkflowItem`, which was populated with any additional, system-generated data (for example, a unique ID).

Note

Invoking this method commits a `WorkflowItem` regardless of any active transition sessions. It bypasses the exclusivity granted to those clients, which have successfully obtained `TransitionSessionTokens`, to add the item.

### Retrieve a WorkflowItem

To retrieve a specific instance of `WorkflowItem`, which was previously added through the platform, use the `Get(WorkflowItemId)` method. This method accepts an instance of the `WorkflowItemId` class, which identifies the `WorkflowItem` to be retrieved. It returns the instance of the `WorkflowItem` class corresponding to that identifier.



If the requested `WorkflowItem` cannot be found, a `WorkflowItemDoesNotExistException` occurs.

In the previous example, the request to retrieve a workflow item is invoked synchronously. An example of retrieving a workflow item asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



To retrieve a collection of `WorkflowItem`s, which have previously been added through the platform, use the `Get(Criteria<WorkflowItemFilter>)` method. This method accepts an instance of `Criteria<WorkflowItemFilter>`, which contains the specifications necessary to retrieve the desired `WorkflowItems`.

The `Filter` property of the `Criteria<WorkflowItemFilter>` class accepts an instance of the `WorkflowItemFilter` class. This class exposes properties representing the specifications that let you refine the result set of `WorkflowItems` you wish to retrieve. `WorkflowItemFilter` properties include:

  • `Target` – Assigning a value (`Reference`) to this property refines a result set to `WorkflowItem`s with a `Target` matching that value. The result set represents the complete moderation history for the entity identified by the specified reference.

  • `State` – Assigning a value (`WorkflowState`) to this property refines a result set to `WorkflowItem`s with a state matching that value.

  • `Workflow` – Assigning a value (`WorkflowId`) to this property refines a result set to `WorkflowItem`s with a `Workflow` matching that value. The result set represents the complete moderation history for all entities under moderation within the identified Workflow.

  • `ExcludeHistoricalItems` – Assigning a value (Boolean) to this property indicates whether or not the result set should target only `WorkflowItem`s representing the current state of their associated entity.

The specifications of the `WorkflowItemFilter` may be applied in conjunction with one another. Each specification, which is assigned a value in the filter, further refines the result set (for example, a logical AND). The example below demonstrates the retrieval of a result page of `WorkflowItem`s, identifying entities currently in a "Pending" state.



In the next example, a result page of `WorkflowItems` is retrieved that represents the complete moderation history for the identified entity.



In the previous examples, the request to retrieve workflow items is invoked synchronously. An example of retrieving workflow items asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



For details regarding the use of criteria, including information on paging and sorting, see _Criteria_ in [Discover the platform](🔗).

### Remove a WorkflowItem

To remove a specific instance of `Workflow`, which was previously added through the platform, use one of three methods:

  • `Remove(WorkflowItemId)` – This method accepts an instance of the `WorkflowItemId` class, which identifies the particular `WorkflowItem` to be removed. The result is the deletion of the `WorkflowItem` corresponding to that ID.

    
  • `Remove(WorkflowId)` – This method accepts an instance of the `WorkflowId `class, which identifies the `Workflow` associated with the `WorkflowItems` to be removed. The result is the deletion of all `WorkflowItems` associated with the identified Workflow.

    
  • `Remove(Reference)` – This method accepts an instance of the `Reference` class, which identifies an entity under moderation (`Target`). The result is the deletion of `WorkflowItems` corresponding to the identified entity (that is, the entire moderation history for that entity).

    

Note

The `Remove` methods do not ensure that the removal of the targeted `WorkflowItems` leaves an entity with a valid moderation history. For example, the removal of a `WorkflowItem` may leave an entity with gaps in its moderation history. This gives a developer the freedom to implement features, which lets an administrator undo the transition of an entity under moderation. However, be cautious in applications where the integrity of an entity's moderation history is important.

In the previous examples, the request to remove one of more workflow items is invoked synchronously. Asynchronous methods are available for all the `Remove` overloads described above. An example of asynchronously removing all `WorkflowItems` associated with the identified `Workflow` using the asynchronous overload with C#'s async and await keywords is described below.



## Extend WorkflowItems with composites

A developer can compose `WorkflowItems` with additional data to create rich and powerful moderation experiences. You may need to associate additional information with a `WorkflowItem` to support your application's use cases. The additional information might represent a request, an action, or a resource entering moderation. For example, it might represent a request for membership in an exclusive group, or the content of a comment pending review before it is committed to the system.

Like other Optimizely Community API features, you can extend a `WorkflowItem` with data of your design by creating a Composite. See _Composites_ in [Discovering the platform](🔗).

### Add a composite WorkflowItem

You can save a Composite WorkflowItem by using the `Add<TExtension>(WorkflowItem,TExtension,TransitionSessionToken)` method of `IWorkflowItemService`.

This method accepts:

  • An instance of the `WorkflowItem` class, which describes the new state of the target under moderation.

  • An instance of `TExtension`, which describes custom data with which the `WorkflowItem` will be composed.

  • An instance of the `TransitionSessionToken` class, which indicates that exclusive access to transition the target was successfully obtained. For information on how to obtain a `TransitionSessionToken`, see _Transition Sessions_ in [Moderation Workflows](🔗),

The method returns a new instance of `Composite\<WorkflowItem,TExtension>`, which has been populated with any additional, system-generated data (for example, a unique ID).

Consider the following class, which represents a sample of extension data.



In the example below, a `WorkflowItem` is added with an instance of this extension class to form a composite `WorkflowItem`.



In the above example, the request to add a workflow item is invoked synchronously. An example of adding a workflow item asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



Note

While overloads of the Add method exist, `Add<TExtension>(WorkflowItem,TExtension,TransitionSessionToken)` is the recommended approach for adding a composite `WorkflowItem`. Using this method consistently when implementing moderation strategies helps to ensure the integrity of your workflow.

To add a composite `WorkflowItem`, without regard for any active transition sessions, use the `Add<TExtension>(WorkflowItem,TExtension)` method of `IWorkflowItemService`.

This method accepts:

  • An instance of the `WorkflowItem` class, which describes the new state of the target under moderation.

  • An instance of `TExtension`, which describes custom data with which the `WorkflowItem` is composed.

The method returns a new instance of `Composite\<WorkflowItem,TExtension>`, which was populated with any additional, system-generated data (for example, a unique ID).

Note

Invoking this method commits a `WorkflowItem` regardless of any active transition sessions. It bypasses the exclusivity granted to those clients, which have successfully obtained `TransitionSessionTokens`, to add the item.

Async versions exist for all overloads of the `Add` method to allow for adding workflow items asynchronously.

### Retrieve a composite WorkflowItem

You can retrieve a specific instance of a Composite WorkflowItem, which was previously added through the platform, via the `Get<TExtension>(WorkflowItemId)` method. This method accepts an instance of the `WorkflowItemId` class, which identifies the particular `WorkflowItem` to be retrieved. It returns an instance of the `Composite\<WorkflowItem,TExtension>` class corresponding to that identifier.



If a Composite `WorkflowItem` with the specified ID and extension type cannot be found, a `WorkflowItemDoesNotExistException` occurs.

In the previous example, the request to retrieve a workflow item is invoked synchronously. An example of retrieving a workflow item asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



To retrieve a collection of Composite WorkflowItems, which have previously been added through the platform, use the `Get(CompositeCriteria\<WorkflowItemFilter,TExtension>)` method. This method accepts an instance of `CompositeCriteria\<WorkflowItemFilter,TExtension>`, which contains specifications necessary to retrieve the desired `WorkflowItems`.

The Filter property of the `CompositeCriteria\<WorkflowItemFilter,TExtension>` class accepts an instance of the `WorkflowItemFilter` class. This class contains specifications that let you refine the result set of `WorkflowItems` you want to retrieve.

The `ExtensionFilter` property, of the `CompositeCriteria\<WorkflowItemFilter,TExtension>` class, accepts a `FilterExpression` that lets you specify a Boolean expression to further refine the result set by values represented within your extension data. For more information on this type of filter, see _Composite Criteria_ and _Filtering Composites_ in [Discover the platform](🔗).

Consider the following class, which represents a sample of extension data that could capture the content of a pending comment:



In the example below, a page of `WorkflowItems` composed with `PendingComment` is retrieved for a particular contributor:



In the previous example, the request to retrieve workflow items is invoked synchronously. An example of retrieving workflow items asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



## Best practices for extending WorkflowItems

Think of the thing you are moderating as an _action_ rather than a _resource_. For example, you moderate:

  • the act of publishing a comment, rather than the comment itself.

  • a request to join a group, rather than a user.

The outcome of an action is only relevant _after_ it is approved through moderation. So, maintain a record of that action in your moderation system and only commit its outcome upon approval.

The Command pattern, or similar behavioral software design patterns, can provide a helpful template for encapsulating an action in this manner.

Supplement the action with the data necessary to commit its outcome to the appropriate repository. If that data is extensive, consider designing the data as a delta against a previous version.

Designing your moderation systems in such a manner:

  • Prevents you from permanently committing unapproved versions of resources, which might otherwise lead to complicated data management scenarios.

  • Provides a traceable and potentially replay-able history of actions on entities under moderation.

  • Promotes a maintainable implementation, where the interpretation and execution of a request are decoupled from the state management of your resources.