Tutorial: Conditionally load different workflows
By default, Sitefinity CMS enables you to define workflows per different sites, languages, types of content, and pages. With pages you can go as granular as specifying a different workflow for all pages under a parent page, or even have separate workflows defined for individual pages. Such level of granularity satisfies the requirements for most business cases.
Additionally, the Sitefinity CMS Workflow API provides great flexibility for customizing the workflow behavior even further. For example, you can implement your own logic to load different workflows, based on custom conditions. This tutorial demonstrates how you can extend Sitefinity CMS Workflow functionality to load different workflows based on the user’s role.
Workflow resolution mechanism
The WorkflowDefinitionResolver
class is responsible for loading the different workflows you have defined for your content based on the corresponding conditions. It provides an extensibility point where you can plug your own logic for conditionally loading workflows, and even dynamically load workflows that have not been defined in the system yet. The class exposes two useful virtual methods that you can override – ResolveWorkflowExecutionDefinition
and GetWorkflowExecutionDefinition
.
ResolveWorkflowExecutionDefinition
is responsible for determining which is the most appropriate workflow definition to be used for an item. You can override this method to specify the custom logic that instructs Sitefinity CMS which workflow to load based on the current context of the user. For example, this is where you can tell Sitefinity CMS to load a desired workflow based on the content type and user role.
GetWorkflowExecutionDefinition
returns a workflow definition from cache (or database if a cached version does not exist) for a given workflow definition Id. When Sitefinity CMS calls this method, the logic for determining which workflow to load has already executed, and GetWorkflowExecutionDefinition
is responsible for delivering the workflow definition. By overriding this method, you can alter the default behavior and return a desired workflow definition. For example, if you have dynamically created a workflow definition, which is not persisted in the database (let’s say your logic is to have different workflow for each role – there really is no need to persist them in the database and complicate editing the rest of the workflows, when you can only load them dynamically), by overriding GetWorkflowExecutionDefinition
you can return that definition safely.
Both methods return objects of type WorkflowDefinitionProxy
– a wrapper for IWorkflowExecutionDefinition
, which hold the parameters necessary for the workflow to execute.
Conditionally load different workflows
To load different workflow based on the user role you must start by creating a custom definition resolver that inherits from the WorkflowDefinitionResolver
class. For more information about creating workflow definitions see: Create workflow definitions.
In the class default constructor, you can create your custom workflow definitions. Any workflow definition you create in the construction will be instantiated when you start your Sitefinity CMS website and will live in the application memory.
Implement the conditional loading behavior
Next, we want to have the following behavior in place:
- Load the "2-step workflow for Restricted Users" for users that are working with any content, and belong to the “RestrictedUsers” role
- Load the “1-step workflow for Bloggers” for users that are working with Blog Posts, and belong to the “Bloggers” role
- Load a default workflow (no approval needed) for users that are working with any content, and belong to the “SpecialUsers” role
- Load a workflow we have already created in the Sitefinity CMS backend UI, called “MyWorkflow” for users that belong to the “SampleUsers” role
- Proceed with the Sitefinity CMS default logic of resolving a workflow if none of the above conditions are met
To achieve the above described behavior, you must override the ResolveWorkflowExecutionDefinition
method and implement your custom logic that matches the desired behavior. In the overridden ResolveWorkflowExecutionDefinition
you can use the Sitefinity CMS Security API to get the current user via ClaimsManager.GetCurrentIdentity
and check whether the user belongs to any of the desired roles.
- If the user belongs to RestrictedUsers, you must return the dynamically created workflow definition for "2-step workflow for Restricted Users".
- If the user belongs to the Bloggers role, you must add an additional check whether the content type they are currently working with is blog posts. This is done via the
IWorkflowResolutionContext
parameter that the ResolveWorkflowExecutionDefinition
method takes. The context contains a ContentType
property, which is equal to the type of the Sitefinity CMS content the user is currently working with. If the value is BlogPosts
, you must return the “1-step workflow for Bloggers” respectively.
- If the user belongs to SpecialUsers role, you must return the default no-approval-needed workflow. This can be done via the
DefaultWorkflow
property of the WorkflowDefinitionProxy
class.
- To return the already defined “MyWorkflow “, if the user belongs to SampleUsers role, you must query the workflow definitions store din yoru Sitefinity CMS database, via the
WorkflowManager
, and get the one whose Title
matches “MyWorkflow"
- Finally, if none of the logical conditions you’ve implemented match, you must implement a call to the base method which will pass the control back to the default Sitefinity CMS logic.
The following sample demonstrates the full implementation of the above scenario:
Replace the default WorkflowDefinitionResolver
Finally, to instruct Sitefinity CMS to use your custom WorkflowDefinitionResolver instead fo the default one, you need to register it in the ObjectFactory container in Global.asax: