Umbraco Forms
13.forms.latest (LTS)
Ask or search…

Adding A Workflow Type To Umbraco Forms

This builds on the "adding a type to the provider model" chapter
Add a new class to your project and have it inherit from Umbraco.Forms.Core.WorkflowType, and implement the class. For this sample, we will focus on the execute method. This method processes the current record (the data submitted by the form) and have the ability to change data and state.
using Serilog;
using System;
using System.Collections.Generic;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Data.Storage;
using Umbraco.Forms.Core.Enums;
using Umbraco.Forms.Core.Persistence.Dtos;
using Microsoft.Extensions.Logging;
using Umbraco.Core.Composing;
namespace MyFormsExtensions
public class TestWorkflow : WorkflowType
private readonly ILogger<TestWorkflow> _logger;
public TestWorkflow(ILogger<TestWorkflow> logger)
_logger = logger;
this.Id = new Guid("ccbeb0d5-adaa-4729-8b4c-4bb439dc0202");
this.Name = "TestWorkflow";
this.Description = "This workflow is just for testing";
this.Icon = "icon-chat-active";
this.Group = "Services";
public override Task<WorkflowExecutionStatus> ExecuteAsync(WorkflowExecutionContext context)
// first we log it
_logger.LogDebug("the IP " + context.Record.IP + " has submitted a record");
// we can then iterate through the fields
foreach (RecordField rf in context.Record.RecordFields.Values)
// and we can then do something with the collection of values on each field
List<object> vals = rf.Values;
// or get it as a string
//Change the state
context.Record.State = FormState.Approved;
_logger.LogDebug("The record with unique id {RecordId} that was submitted via the Form {FormName} with id {FormId} has been changed to {RecordState} state",
context.Record.UniqueId, context.Form.Name, context.Form.Id, "approved");
return Task.FromResult(WorkflowExecutionStatus.Completed);
public override List<Exception> ValidateSettings()
return new List<Exception>();

Information available to the workflow

Record information

The ExecuteAsync() method gets a WorkflowExecutionContext which has properties for the related Form, Record, and FormState. This parameter contains all information related to the workflow.
The Record contains all data and metadata submitted by the form. As shown in the example above, you can iterate over all RecordField values in the form. You can also retrieve a specific record field by alias using the following method:
RecordField? recordField = context.Record.GetRecordFieldByAlias("myalias");
Having obtained a reference to a record field, the submitted value can be retrieved via:
var fieldValue = recordField.ValuesAsString(false);
The ValuesAsString will JSON escape the result by default. If you do not want this escaping to occur, pass false as the parameter.
If the field stores multiple values, they are delimited with a comma. In many cases, you can safely split on that delimiter to obtain the individual values. However, this can lead to issues if the prevalues being selected also contain commas. If that's a concern, the following extension method is available in Umbraco.Forms.Core.Extensions to correctly parse the selected prevalues:
IEnumerable<string> selectedPrevalues = recordField.GetSelectedPrevalues();

Form and state information

The Form references the form the record is from and FormState provides its state (submitted or approved).
Other context, such as the current HttpContext, if needed can be passed as constructor parameters (for example: the HttpContext can be accessed by injecting IHttpContextAccessor).

Registering the workflow type

To use the new workflow type, you will need to register it as part of application startup.
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Forms.Core.Providers;
namespace MyFormsExtensions
public class Startup : IComposer
public void Compose(IUmbracoBuilder builder)