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


In the Optimizely Community API, your moderation strategy is represented as a workflow. The platform provides a simple set of tools for defining these workflows.



A workflow is comprised of:

  • A set of states. For example: "Pending", "In Review", "Rejected", "Published".

  • Actions. For example: "Accept", "Ignore", "Reject", "Publish".

  • Transitions, the combination of two states (origin and destination) and an action, which causes the transition to occur. For example, an item's state is "Pending" (_origin state_), a reviewer accepts the request (_action_), changing its state to "In Review" (_destination state_).

## Define a workflow

To define a workflow in the Optimizely Community API, use the `Workflow` class.

An instance of the `Workflow` class is constructed with a name, an initial state (represented by the `WorkflowState` class), and a collection of transitions (represented by the `WorkflowTransition` class). Together, they represent a complete workflow.

Consider the example workflow in the diagram above. An instance of the `Workflow` class can be constructed to represent it as follows:



The `Workflow` class exposes several methods to further support the development of moderation features. The methods let you enforce the workflow process. They also help you construct the user experiences involved in workflow management.

  • `ActionsFor` – For any state, this method lets you discover available actions, as governed by the workflow.



In this method, you provide a state ("Pending" in the example above), and it returns available actions according to the workflow's definition. Continuing the above example, when requesting actions for an entity in "Pending" state, the method returns the two available actions: "Accept" and "Ignore".

You might use these actions to create a UI with buttons that illustrate actions that may be taken on an entity under moderation. For example, you are moderating a group membership request whose state is "In Review." To draw a UI that shows possible actions for "In Review" requests, leverage the ActionsFor method to discover available actions.

  • `Transition` – For an action occurring on an entity in a particular state (origin), this method identifies the resulting state (destination).



In this method, you provide an origin state (WorkflowState) and an action (WorkflowAction). The method returns the destination state (WorkflowState). Continuing the above example, given an origin state of "Pending" and an action of "Accept", a destination state of "In Review" is returned.

Note

The method simply identifies the resulting state. No state change is persisted as a result of invoking this method.

If an action is specified which is not available in the given state, an InvalidActionOnWorkflowItemException is thrown. To discover the list of available actions, leverage the ActionsFor method.

This method is leveraged in the development of features managing the transition of entities through a moderation workflow.

  • `HasState` – Indicates whether or not the specified state exists within this workflow.



In this method, you provide a state ("Pending" in the example above), and it returns a boolean indicating whether or not that state exists in this workflow.

## Manage workflows

In the Optimizely Community API, workflows are managed through a service implementing the `IWorkflowService` interface. The workflow service provides the ability to persist and retrieve workflows that you define.

  • Accessing the workflow service

  • Adding a workflow

  • Retrieving a workflow

  • Removing a workflow

  • Transition sessions

This service lets you persist, retrieve, and remove workflows you define.

### Access the workflow service

If the Moderation feature is installed to an Optimizely CMS site with the site integration package, 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, get an instance of this service from the default `factory` class provided in the package.

Example:



### Add a workflow

You can save a workflow which you defined via the `Add(Workflow)` method of `IWorkflowService`. This method accepts an instance of the `Workflow` class and returns a reference to a new instance of this class, which has been populated with additional, system-generated, data (for example, a unique ID).



To successfully add a workflow, the transitions for that workflow cannot contain duplicate entries with identical combinations of From and To state. Also, the initial state of the workflow being added must match either the From or the To state of at least one of the workflow transitions.

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



### Retrieve a workflow

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



If the requested workflow cannot be found, a `WorkflowDoesNotExistException` is thrown.

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



You can retrieve a collection of workflows that were previously added through the platform via the `Get(Criteria<WorkflowFilter>)` method. This method accepts an instance of `Criteria`, which contains specifications necessary to retrieve the desired Workflows.

The `Filter` property of the `Criteria<WorkflowFilter>` class accepts an instance of the `WorkflowFilter` class. This class contains specifications that allow you to refine the result set of workflows you wish to retrieve.



In the example above, criteria is defined to request a result page of workflows that share the name "My Workflow". The criteria is provided to the workflow service, and a `ResultPage` is returned with a collection of workflows that match the criteria.

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



For details on using criteria, including information on paging and sorting, see _Criteria_ in [Discovering the platform](🔗).

### Remove a workflow

To remove a specific instance of workflow previously added through the platform, use the `Remove(WorkflowId)` method. This method accepts an instance of the `WorkflowId` class, which identifies the workflow to be removed. The result is the deletion of the workflow corresponding to that ID.



You cannot remove a workflow if related `WorkflowItems` exist. So, remove all `WorkflowItems` related to a workflow before attempting to remove it.

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



### Transition sessions

The moderation schemes of applications vary greatly. Some are simple, with few operations to transition their targets from state to state. Others are more complex, involving many operations and custom business logic. Regardless of the complexity of your moderation scheme, the integrity of that scheme is important. Your application may be receiving requests concurrently, whether it's on the same server or distributed across multiple servers.

As an example, consider a scenario where two moderators within your application attempt to moderate a request to join a group simultaneously. They see the same request in the same state. One approves the request while the other rejects it. If the application allows both moderators to succeed, the request will very likely end up in an unexpected state.

Your application needs to ensure that moderation occurs in a controlled manner. To prevent situations such as the one described above, the application needs the opportunity to obtain exclusive access to a target of moderation. In doing so, the application can perform the operations, queries, and evaluations necessary to transition that target through a workflow. The Optimizely Community API allows an application to request exclusive access to a target of moderation, within a particular workflow, such that the application can execute its logic without jeopardizing the integrity of the target's state.

#### Moderate with transition sessions

##### Begin a transition session

To request exclusive access to a target of moderation, use the `BeginTransitionSession(WorkflowId, Reference)` method of `IWorkflowService`. This method accepts:

  • An instance of the `WorkflowId` class, which identifies the `Workflow` being used for moderation.

  • An instance of the `Reference` class, which identifies the target under moderation. This is the target to which exclusive access is desired.

If exclusive access is successfully acquired, a `TransitionSessionToken` is returned. This token is used to identify your session when you add a `WorkflowItem` for the target.

If exclusive access is _not_ successfully acquired, a `TransitionSessionDenied` exception is thrown. Access is denied if:

  • Exclusive access has already been granted for the identified target in the specified workflow.

  • The specified workflow does not exist.

The exception should be handled within the application, in the event that competing requests for access to the identified target are made.

Note

A target need not have a pre-existing moderation history to request exclusive access to it. Exclusive access can also be granted to a target entering moderation for the first time.

Note

While a transition session grants a client exclusive access to a target in a workflow, it is not a transaction. The operations performed in the course of a transition session are not atomic and are not reverted if an error occurs. It is important to account for the possibility that an error may occur within the application and handle it accordingly.

##### End a transition session

When the application completes its operation, it should relinquish its exclusive access to the target so that other clients may obtain it. To end a transition session, use the `EndTransitionSession(TransitionSessionToken)` or `EndTransitionSession(WorkflowId, Reference)` method of `IWorkflowService`.

The `EndTransitionSession(TransitionSessionToken)` method accepts:

  • An instance of `TransitionSessionToken` identifying the specific session to end. Provide the token that the application received when it called the `BeginTransitionSession` method.

The `EndTransitionSession(WorkflowId, Reference)` method accepts:

  • An instance of `WorkflowId`, which identifies the `Workflow` being used for moderation.

  • An instance of `Reference`, which identifies the target under moderation.

##### Example of a transition session

In the implementation of a moderation strategy for an application, a transition session typically involves these actions:

  1. Retrieve the workflow, under which the target is moderated.

  2. Begin a transition session for the target in that workflow.

  3. Retrieve the current state of that target in the workflow.

  4. Given the moderation action to be applied, use the workflow to determine the next state of that target in the workflow.

  5. Transition the target to a new state by adding a new `WorkflowItem`.

  6. End the transition session.

The example below demonstrates the implementation of a moderation strategy, which leverages transition sessions to ensure that its targets are moderated in a protected manner.



In the above moderation example, the requests to begin and end the transition are invoked synchronously. An example of performing these activities asynchronously using the asynchronous overload with C#'s async and await keywords is described below.



## Extend workflows with composites

You may need to associate additional information with a workflow to support your application's use cases. For example, if a workflow is intended to support the moderation of a group, you might store the group's identifier to dynamically interpret their relationship.

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

This section explains, both, the synchronous and asynchronous APIs of the workflow service that provide support for extending workflow items with composites.

### Add a composite workflow

To save a composite workflow which you defined, use the `Add<TExtension>(Workflow,TExtension)` method of `IWorkflowService`. This method accepts an instance of the `Workflow` class and an instance of `TExtension`. It returns a new instance of `Composite\<Workflow,TExtension>`.

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



In the example below, a simple workflow is composed with an instance of this extension class:



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



### Retrieve a composite workflow

To retrieve an instance of a composite workflow which was previously added through the platform, use the `Get<TExtension>(WorkflowId)` method. This method accepts an instance of the `WorkflowId` class, which identifies the workflow to be retrieved. It returns the instance of the `Composite\<Workflow,TExtension>` class corresponding to that identifier.



If a composite workflow with the specified ID and extension type cannot be found, a `WorkflowDoesNotExistException` is thrown.

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



To retrieve a collection of composite workflows, which were previously added through the platform, use the `Get<TExtension>(CompositeCriteria\<WorkflowFilter, TExtension>)` method. This method accepts an instance of `CompositeCriteria\<WorkflowFilter,TExtension>`, which contains the specifications necessary to retrieve the desired Workflows.

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

The `ExtensionFilter` property of the `CompositeCriteria\<WorkflowFilter,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:



In the example below, a page of workflows composed with `MyWorkflowExtension` is retrieved, where the `Department` property of that extension data has a value of _Finance_.



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



## Best practices for extending workflows

### Relationships

In scenarios where your application must dynamically interpret the relationship between a workflow and some other entity, leverage composites to persist the data necessary to resolve that association. For example, if a workflow is intended to moderate group membership, define extension data that captures the group's ID and stores that information with the workflow as a composite.

### Act on transitions

Often, your application must execute business logic due to a transition within a workflow. You might implement stateless strategy methods within the extension data that you associate with your workflow. This provides easy access to logic that can be dynamically executed upon committing a transition.