Issues with configuring approval workflows in EPiServer

Ever since the release of EPiServer CMS 5, workflow within EPiServer CMS has been based on Microsoft’s Workflow Foundation. Out of the box EpiServer comes with four pre-configured workflows:

  • Sequential Approval
  • Parallel Approval
  • Request For Feedback
  • Ready For Translation

Issues with the approval workflows

The sequential and parallel approval workflows are designed to regulate the publishing of pages within the website. However, there are a couple of features with the out of the box design that could cause issues if you want to use these approval workflows to automatically regulate the publishing of pages on your website.

1. These workflows required that any approvers have to have publish access to that page.

This means that approvers can bypass the workflow system and publish the page before it has gone through all it’s stages.

2. The workflows do not check if there is an existing workflow instance for that page before creating a new one.

If a page is set to “Not Approved” a task is created for the original editor which allows them to send the workflow back to the approvers. If an edit is done, this workflow can be associated with the new version of the page. The trouble comes if you have set the workflow to be created by one of the events involved with the editing process (either Save or Ready to Publish) then a new instance of the workflow will be created, leading to multiple instances of the workflow for a page.

Getting workflows to work

Getting the approval workflows to work in a more logical way is not easy because of the highly bound way that EPiServer built the workflow system.

Step 1. New Approval Service

To remove the requirement for an approver to have publish access, the HasReadAndPublishRights method of the EPiServer.WorkflowFoundation.Workflows.ApprovalService class needs to be modified. Although the method is public it is not virtual, and because of how it is accessed internally and externally, inheriting from it and marking the new method as new will not work. The only solution is to copy the source into a replacement class and edit the HasReadAndPublishRights method to remove the checks for Publish access.

EPiServer.Config will need to be updated replacing the <externalService> entry for the EPiServer ApprovalService with your new one.

Step 2. Replacing the workflow dialogs

Unfortunately this is only the start of the issues. There is a tight coupling between the ApprovalService class and the controls used to display the task forms. To get around this, a number of ascx files need to be copied from the CMS/edit folder into a folder in your web project:

  • WorkflowApprovalStart.ascx
  • WorkflowApprovalEvent.ascx
  • WorkflowTaskControl.ascx
  • WorkflowHistoryList.ascx
  • WorkflowApprovalVersion.ascx

To redirect calls from the original controls to the new ones we can use the EPiServer virtual path mapping provider.

<virtualPath customFileSummary="~/FileSummary.config">
    <providers>
    ....
    <add showInFileManager="false" virtualName="WFMapping" virtualPath="~/episerver/CMS"
        bypassAccessCheck="false" name="WFMapping"
        type="EPiServer.Web.Hosting.VirtualPathMappedProvider,EPiServer"/>
    </providers>
    <filters />
</virtualPath>
<virtualPathMappings>
    <add url="~/episerver/CMS/edit/WorkflowApprovalStart.ascx"
        mappedUrl="~/controls/workflow/WorkflowApprovalStart.ascx"/>
    ....
</virtualPathMappings>

The source of WorkflowApprovalStart.ascx and WorkflowApprovalEvent.ascx both need copying into new class files and the controls edited to use them. This is so they can be pointed to use the new ApprovalService class.

The WorkflowTaskControl.ascx source code needs to be copied and the TryLoadControlFromAttribute method needs modifying. This method looks at an workflow activity and loads the control specified by it’s ActivityPlugIn attribute. Unfortunately this URL will point to the original controls not your new ones. Modifying this method to use the VirtualPathMappings configuration settings to look up the new control URL and use this to load the new control.

The WorkflowHistoryList.ascx and WorkflowApprovalVersion.ascx can be left as is as they are only there to make WorkflowTaskControl.ascx compile.

Step 3. Only one workflow instance per page

As described above there are a few scenarios that could lead to a page having multiple running workflow instances.

Both of the approval workflows use an IsValidParameter method to check if the workflow has the right parameter settings to be assigned to approvers or, if not, just closed. Modifying this to check if there is a running workflow instance, other than the current one, already exists and returning false if it does. This stops multiple running workflow instances existing for the same page.