v5.0-v6.0
To migrate from versions 5.0 or higher, you must go directly to version 6.0. Migration to intermediate versions is not supported. Below are considerations to keep in mind according to the version of Qflow from which you are migrating. These considerations are incremental, meaning that if, for example, you are migrating from 5.0, you must take into account the considerations for 5.0, then the considerations for 5.1.1, and so on.
Migration considerations from Qflow 5.0
SQL Server database version
Starting from this version, SQL Server 2016 or higher is required to install and work with Qflow databases. Additionally, Oracle will no longer be supported.
Migration considerations from Qflow 5.1.1
Method signature change in Flow and Attachment controllers
In version 5.2 several Flow and Attachment controller signatures were changed to asynchronous calls. In this way, instead of returning a T object, a Task<T> object will be returned. Special care must be taken if custom forms were developed. All the references to these methods may need some adjustment.
- The list of changed methods in the Flow controller is the following:
Start
Edit
DisplayTask
StartFlow
StartFlowAndGetSimpleData
EditFlow
RespondTask
- The list of changed methods in the Attachment controller is the following:
UploadAttachment
AddFlowAttachment
Download
Unified session across sites
In version 5.2 of Qflow, sites can have a unified session, meaning that when a user logs in to Qflow Design and has permissions in Qflow Team, accessing Qflow Team goes directly to the home page without going through the login. If you want to avoid this behavior on some sites, you simply have to add two appsettings to the corresponding web.config file.
- These are:
UseUnifiedSession: if you don’t want to use it, it must have the value ‘false’
OwinCookieName: this is the name of the cookie that will be used by the site, it can be assigned any value other than the unified session cookie value (QflowAuth). For example: QflowDesignerAuth, QflowTeamAuth, etc.
New system parameters
A series of system parameters were added in this version that change the behavior of Qflow. Each of these parameters should be reviewed to ensure that everything functions correctly.
- The parameters are the following:
QflowBPMWebLink/QflowOMMLink/QflowSAMWebLink/QflowWebSiteLink: These parameters must be adjusted to the urls used by the different Qflow tools. Without them, the navigation between sites that can be found in the right section of the headers will not work correctly.
NotifyUserOnCreation: If this parameter is True, Qflow will send a welcome email to the mailbox of the created user.
UserWelcomeLink: It is the link that is sent to new users if the NotifyUserOnCreation parameter is enabled. If you want to use it, it must be adjusted to the url of the desired site. It is recommended to use the Qflow Access url.
Logo/LogoLightVersion/TaskMiniLogo/TaskLogo: Different parameters corresponding to the tools logos have been added. Now the Logo parameter corresponds to the Qflow logo and will be shown in the login of each tool, as well as in the upper left part of Qflow Access. If you want to change the Qflow Task logo, now you must change the TaskLogo parameter.
Migration considerations from Qflow 5.2
Changes in custom forms
Asynchronous methods in custom forms
Many of the methods used to invoke actions, such as obtaining the start form of a process, responding to a task, or editing a process, have been changed to asynchronous methods. This means that changes need to be made to the forms that use them to make them work.
Warning
Given these changes, it is important to note that depending on how it is implemented, the methods might not produce compilation errors. Developers creating forms might not notice issues, however, undesired effects may occur if the await instructions are not added where appropriate.
You can see these changes reflected in the controllers section of the custom form design manual.
Support for anonymous/external flow start and task response in custom forms
Now it’s possible to use custom forms for the start or response of external/anonymous tasks. To ensure existing custom forms continue to work with these types of actions, modifications will need to be made to the process start forms and task response forms.
The first thing to do is update the ViewStart file with the necessary changes for these types of forms. This involves adding the condition for the new layout, CustomFormsGuestLayout, to this file. The file should look like this:
{ if (Qframework.Web.Mvc.SessionManagement.SessionManagerHelper.GetSessionManager<Qflow.Web.Mvc.SessionManagement.QflowSessionManager>().IsGuest) { Layout = "~/Views/Shared/_CustomFormsGuestLayout.cshtml"; } else if (Request.QueryString["useEmptyLayout"] == null || Request.QueryString["useEmptyLayout"] !="True") { Layout = "~/Views/Shared/_CustomFormsLayout.cshtml"; } else { Layout = "~/Views/Shared/_CustomFormsEmptyLayout.cshtml"; } }
For both start and response forms, you should include a reference to the Qflow.Mvc.Multitenancy library in their views. You can do this by adding the following line to the list of usings at the beginning of the view file:
@using Qflow.Mvc.Multitenancy
For the views of flow start forms, replace the following:
@using (Html.BeginForm(null, null, new { templateId = Model.TemplateId, useEmptyLayout = Request.QueryString["useEmptyLayout"] },
FormMethod.Post, new { id = "submitForm", enctype = "multipart/form-data" }))
for the following code:
@using (Html.BeginForm(null, null, new { templateId = Model.TemplateId, useEmptyLayout = Request.QueryString["useEmptyLayout"],
tenantId = TenantResolver.GetRequestTenantIdOrDefault() }, FormMethod.Post, new { id = "submitForm", enctype = "multipart/form-data" }))
For the views of task response forms, replace the following:
if (Request.QueryString["DisplayLinks"] == null || bool.Parse(Request.QueryString["DisplayLinks"]))
{
ViewBag.Links = ModelHelper.GetPageLinks("DisplayTask", Model.FlowId, Guid.Empty, Model.VersionId, Url);
}
for the following code:
var isGuest = Model is GuestTaskModel;
var displayLinks = Request.QueryString["DisplayLinks"] == null || bool.Parse(Request.QueryString["DisplayLinks"]);
if (!isGuest && displayLinks)
{
ViewBag.Links = ModelHelper.GetPageLinks("DisplayTask", Model.FlowId, Guid.Empty, Model.VersionId, Url);
}
Also, replace:
@using (Html.BeginForm(null, null, new { flowId = Model.FlowId, taskId = Model.FlowStepId,
taskToId = Model.FlowStepToId, useEmptyLayout = Request.QueryString["useEmptyLayout"] }, FormMethod.Post,
new { id = "submitForm", enctype = "multipart/form-data" }))
for the following:
@using (Html.BeginForm(null, null, new { flowId = Model.FlowId, taskId = Model.FlowStepId,
taskToId = Model.FlowStepToId, useEmptyLayout = Request.QueryString["useEmptyLayout"],
tenantId = TenantResolver.GetRequestTenantIdOrDefault() }, FormMethod.Post,
new { id = "submitForm", enctype = "multipart/form-data" }))
For task response forms, we also need to include the QGuest helper in the view as follows:
@Html.QGuest(Request)
Change in “Manage links” permission
Since the “Links” functionality in Qflow Task was removed in version 5.5 and replaced by the “Customize the sidebar menu” functionality, the “Manage links” permission at the installation level was also replaced by the new “Manage the sidebar menu” permission. For environments where the WebForms site is used, this permission will need to be added again so that users can continue using the “Links” functionality on the WebForms site.
Nullable properties of work queue configuration objects
The “ValidFrom” and “ValidTo” properties of the WorkQueueConfiguration objects, which are returned by methods that provide information about organizational nodes in the web services, are now nullable objects. Therefore, users who utilize them need to take this consideration into account.
New system parameters
A series of system parameters were added in this version that change the behavior of Qflow. Each of these parameters should be reviewed to ensure that everything functions correctly.
- The parameters are the following:
StartFlowAsGuestLink: Format of links for starting anonymous/external flows. This parameter is unique per installation and should not be modified to ensure correct functionality.
GuestResponseLink: Format of links for external task responses dispatched to external users. An instance of this parameter is added for each workspace and should not be modified to ensure correct functionality.
Changes in web.config files for sites and backend API
The web.config files for the sites and backend API have changes in their assemblyBinding properties. You can perform a clean installation and review the installed files to see what these properties are.
New configurations have been added that need to be included in the web.config file of the Qflow Task site. These configurations should be added under the configuration/appSettings section of the file.
Table export configuration: the following configuration related to table export should be included in the site’s web.config file:
<!-- Table export config --> <add key="ExportFormats" value="csv,html,excel" /> <add key="ShowTableExportAsButtons" value="false" />
The ExportFormats property allows us to choose which export formats are permitted for exporting tables. We can remove some of the values shown above if we want to disable the option to export in that format. The ShowTableExportAsButtons property allows us to configure whether the export options are shown as separate actions or grouped in a dropdown list.
reCaptcha configuration for starting external/anonymous flows: The following configuration should be included to enable a reCaptcha challenge for starting external/anonymous flows:
<!-- ReCAPTCHA config --> <add key="ReCAPTCHASiteKey" value="" /> <add key="ReCAPTCHASecretKey" value="" /> <add key="ReCAPTCHAVerifyUrl" value="https://www.google.com/recaptcha/api/siteverify?secret={{0}}&response={{1}}" /> <add key="ReCAPTCHARenderUrl" value="https://www.google.com/recaptcha/api.js?onload=onReCaptchaLoad&render=explicit" />
To enable the reCaptcha challenge, we need to fill in the values for the ReCAPTCHASiteKey and ReCAPTCHASecretKey properties. You can read about how to obtain these values here.
The following property is added to the system.config file, found in the installation directory of the Qflow backend services, under the configuration section:
<SecurityProperties> <TokenEncryptionPepper></TokenEncryptionPepper> </SecurityProperties>
What is provided as the value for this property, within the TokenEncryptionPepper node, is added to the secrets before encrypting them, as an extra security measure to make decryption more difficult.
Migration considerations from Qflow 5.5
System time zone
Now Qflow has a configured system time zone in which dates will be stored. It is necessary to configure this zone correctly so that dates are displayed correctly in the different tools. Keep in mind that, once configured, it cannot be changed without performing a manual data migration.
Scripting interface
The C# scripting interface has been updated to support the new date and time zone handling. Pre-existing methods return dates in the system time zone as a DateTime object. It is recommended to verify and adapt codes that use them to adjust to this behavior.
JavaScript library
The JavaScript library has been updated to support the new date and time zone handling. Pre-existing methods return dates in the system time zone. It is recommended to verify and adapt codes that use them to adjust to this behavior.
New sites for the Form Designer
Version 6.0 introduces new sites for the Form Designer, which are included in the Qflow installers. These sites are:
Qflow Form: This site is the new custom form designer. It has its own backend and frontend.
Qflow Task Angular: This site is a new partial version of the existing Qflow Task site. It has separate backend and frontend.
Event Hub: This site handles event synchronization between Qflow sites.
The backends of Qflow Form and Qflow Task Angular, along with the Event Hub site, require the configuration of a new application pool with the No Managed Code option. Each of these application pools must be exclusive to its corresponding site and not shared with other sites. Additionally, all three application pools must use the same user as the Qflow.Backend.API application pool.
These new sites use .NET 8 and node 24. Additionally, infrastructure must be available for a new SQL Server database (installed together with the Qflow database update).
Attachment storage
Starting from this version, Qflow incorporates new options for attachment storage, including the ability to use Amazon S3 and to configure multiple external databases to distribute the storage load.
These new features require adjustments to the system configuration if storage in an external database or Azure Blob Storage was already being used. In those cases, it will be necessary to transfer the configuration previously defined in the System.config file to the Qflow database, following the instructions in Attachments storage.
Deprecated properties
In order to simplify the configuration of template steps in Qflow Design, some properties with limited use have been deprecated. Below are SQL queries that allow you to identify the steps that use these properties, so that they can be reviewed and adjusted if necessary. The deprecated properties are Start flag, End flag, Process importance, and Progress.
These queries will return the template steps that use the deprecated properties, along with relevant information such as the step identifier and name, the template identifier and name, the version identifier and name, and the tenant identifier. The behavior provided by these properties can be easily replicated using application data. For example, it is possible to add an application data item called “Progress”, whose value is updated in the steps that previously used the “Progress” configuration.
Start flag:
SELECT tsb.TemplateStepID, tsb.Name as TemplateStepName, tsb.ConfigurationXml, t.PackageID as TemplateId, t.Name as TemplateName, v.PackageID as VersionId, v.Name as VersionName, tsb.TenantID FROM TemplateStepBase tsb inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID WHERE ConfigurationXml.exist('//*[local-name()="StartFlag" and text() != ""]') = 1;
End flag:
SELECT tsb.TemplateStepID, tsb.Name as TemplateStepName, tsb.ConfigurationXml, t.PackageID as TemplateId, t.Name as TemplateName, v.PackageID as VersionId, v.Name as VersionName, tsb.TenantID FROM TemplateStepBase tsb inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID WHERE ConfigurationXml.exist('//*[local-name()="EndFlag" and text() != ""]') = 1;
Progress:
SELECT tsb.TemplateStepID, tsb.Name as TemplateStepName, tsb.ConfigurationXml, t.PackageID as TemplateId, t.Name as TemplateName, v.PackageID as VersionId, v.Name as VersionName, tsb.TenantID FROM TemplateStepBase tsb inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID WHERE ConfigurationXml.exist('//*[@Progress and not(@Progress="0")]') = 1;
Flow importance:
SELECT tsb.TemplateStepID, tsb.Name as TemplateStepName, tsb.ConfigurationXml, t.PackageID as TemplateId, t.Name as TemplateName, v.PackageID as VersionId, v.Name as VersionName, tsb.TenantID FROM TemplateStepBase tsb inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID WHERE ConfigurationXml.exist('//*[@Importance and not(@Importance="Empty")]') = 1;