We have moved!

You are currently looking at documentation for Umbraco 8 and older versions.
Go to docs.umbraco.com for documentation for Umbraco 9 and newer versions.

    Customize Default Workflows For a Form

    The default behavior when a new form is created is for a single workflow to be added, which will send a copy of the form to the current backoffice user's email address.

    From versions 8.13 it's possible to amend this behavior and change it to fit your needs.

    Implementing a Custom Behavior

    The interface IApplyDefaultWorkflowsBehavior is used to abstract the logic for setting default workflows for a form. The default behavior is defined using a built-in, internal class that implements this interface.

    You can create your own implementation of this interface. An illustrative example of this, adding a custom workflow that writes to the log, is shown below.

    Firstly, the custom workflow:

    using System;
    using System.Collections.Generic;
    using Umbraco.Core.Composing;
    using Umbraco.Core.Logging;
    using Umbraco.Forms.Core.Attributes;
    using Umbraco.Forms.Core.Enums;
    using Umbraco.Forms.Core.Persistence.Dtos;
    
    namespace MyNamespace
    {
        public class TestWorkflow : WorkflowType
        {
            public const string TestWorkflowId = "7ca500a7-cb34-4a82-8ae9-2acac777382d";
    
            public TestWorkflow()
            {
                Id = new Guid(TestWorkflowId);
                Name = "Test Workflow";
                Description = "A test workflow that writes a log line";
                Icon = "icon-edit";
            }
    
            [Setting("Message", Description = "The log message to write", View = "TextField")]
            public string Message { get; set; }
    
            public override List<Exception> ValidateSettings()
            {
                var exs = new List<Exception>();
                if (string.IsNullOrEmpty(Message))
                {
                    exs.Add(new Exception("'Message' setting has not been set"));
                }
    
                return exs;
            }
    
            public override WorkflowExecutionStatus Execute(Record record, RecordEventArgs e)
            {
                Current.Logger.Info<TestWorkflow>($"'{Message}' written at {DateTime.Now}"); ;
                return WorkflowExecutionStatus.Completed;
            }
        }
    }
    

    Secondly, the custom implementation of IApplyDefaultWorkflowsBehavior:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Umbraco.Core.IO;
    using Umbraco.Forms.Core;
    using Umbraco.Forms.Core.Enums;
    using Umbraco.Forms.Core.Providers;
    using Umbraco.Forms.Web.Behaviors;
    using Umbraco.Forms.Web.Models.Backoffice;
    
    namespace MyNamespace
    {
        public class CustomApplyDefaultWorkflowsBehavior : IApplyDefaultWorkflowsBehavior
        {
            private readonly WorkflowCollection _workflowCollection;
            private readonly IFacadeConfiguration _facadeConfiguration;
    
            public CustomApplyDefaultWorkflowsBehavior(
                WorkflowCollection workflowCollection,
                IFacadeConfiguration facadeConfiguration)
            {
                _workflowCollection = workflowCollection;
                _facadeConfiguration = facadeConfiguration;
            }
    
    
            public void ApplyDefaultWorkflows(FormDesign form)
            {
                // If default workflow addition is disabled in configuration, then exit.
                if (_facadeConfiguration.GetSetting("DisableDefaultWorkflow").ToLower() == "true")
                {
                    return;
                }
    
                // Retrieve the type of the default workflow to add.
                WorkflowType testWorkflowType = _workflowCollection[new Guid(TestWorkflow.TestWorkflowId)];
    
                // Create a workflow object based on the workflow type.
                var defaultWorkflow = new FormWorkflowWithTypeSettings
                {
                    Id = Guid.Empty,
                    Name = "Log a message",
                    Active = true,
                    IncludeSensitiveData = IncludeSensitiveData.False,
                    SortOrder = 1,
                    WorkflowTypeId = testWorkflowType.Id,
                    WorkflowTypeName = testWorkflowType.Name,
                    WorkflowTypeDescription = testWorkflowType.Description,
                    WorkflowTypeGroup = testWorkflowType.Group,
                    WorkflowTypeIcon = testWorkflowType.Icon,
    
                    // Optionally set the default workflow to be mandatory (which means editors won't be able to remove it
                    // via the back-office user interface).
                    IsMandatory = true
                };
    
                // Retrieve the settings from the type.
                Dictionary<string, Core.Attributes.Setting> workflowTypeSettings = testWorkflowType.Settings();
    
                // Create a collection for the specific settings to be applied to the workflow.
                // Populate with the setting details from the type.
                var workflowSettings = new List<SettingWithValue>();
                foreach (KeyValuePair<string, Core.Attributes.Setting> setting in workflowTypeSettings)
                {
                    Core.Attributes.Setting settingItem = setting.Value;
    
                    var settingItemToAdd = new SettingWithValue
                    {
                        Name = settingItem.Name,
                        Alias = settingItem.Alias,
                        Description = settingItem.Description,
                        Prevalues = settingItem.GetPreValues(),
                        View = IOHelper.ResolveUrl(settingItem.GetSettingView()),
                        Value = string.Empty
                    };
    
                    workflowSettings.Add(settingItemToAdd);
                }
    
                // For each settting, provide a value for the workflow instance (in this example, we only have one).
                SettingWithValue messageSetting = workflowSettings.SingleOrDefault(x => x.Alias == "Message");
                if (messageSetting != null)
                {
                    messageSetting.Value = "A test log message";
                }
    
                // Apply the settings to the workflow.
                defaultWorkflow.Settings = workflowSettings;
    
                // Associate the workflow with the appropriate form submission event.
                form.FormWorkflows.OnSubmit.Add(defaultWorkflow);
            }
        }
    }
    

    Finally, to register the custom implementation in place of the default one:

    using Umbraco.Core;
    using Umbraco.Core.Composing;
    using Umbraco.Forms.Web.Behaviors;
    
    namespace MyNamespace
    {
        public class TestSiteComposer : IUserComposer
        {
            public void Compose(Composition composition)
            {
                // Replace the default behavior for associating workflows with a custom implementation.
                composition.RegisterUnique<IApplyDefaultWorkflowsBehavior, CustomApplyDefaultWorkflowsBehavior>();
            }
        }
    }
    

    Setting a Mandatory Default Workflow

    When adding a default workflow in code, it's possible to make it mandatory, which will prevent editors from removing it from a form.

    You can see this in the example above, where the IsMandatory property of the created FormWorkflowWithTypeSettings instance is set to true.