Umbraco Forms
CMSCloudHeartcoreDXP
15.latest
15.latest
  • Umbraco Forms Documentation
  • Legacy Documentation
  • Release Notes
  • Installation
    • Installing Umbraco Forms
    • Licensing
  • Upgrading
    • Upgrading Umbraco Forms
    • Version Specific Upgrade Notes
  • Editor
    • Creating a Form - The basics
      • Form Settings
      • Form Advanced Options
      • Form Information
      • Overview Of The Field Types
        • Date
        • File Upload
        • reCAPTCHA V2
        • reCAPTCHA V3
      • Setting-up Conditional Logic on Fields
    • Attaching Workflows
      • Workflow Types
    • Viewing And Exporting Entries
    • Defining And Attaching Prevalue Sources
      • Prevalue Source Types Overview
  • Developer
    • Property Editors
    • Preparing Your Frontend
    • Rendering Forms
    • Rendering Forms Scripts
    • Themes
    • Custom Markup
    • Email Templates
    • Working With Record Data
    • Umbraco Forms in the Database
    • Extending
      • Adding A Type To The Provider Model
        • Setting Types
      • Adding A Field Type To Umbraco Forms
        • Excluding a built-in field
      • Adding A Prevalue Source Type To Umbraco Forms
      • Adding A Workflow Type To Umbraco Forms
      • Adding An Export Type To Umbraco Forms
      • Adding a Magic String Format Function
      • Adding A Server-Side Notification Handler To Umbraco Forms
      • Adding a Validation Pattern
      • Customize Default Fields and Workflows For a Form
    • Configuration
      • Forms Provider Type Details
    • Webhooks
    • Security
    • Magic Strings
    • Health Checks
      • Apply keys and indexes
      • Apply keys and indexes for forms in the database
    • Localization
    • Headless/AJAX Forms
    • Block List Labels
    • Field Types
    • Storing Prevalue Text Files With IPreValueTextFileStorage
  • Tutorials
    • Overview
    • Creating a Contact Form
    • Creating a Multi-Page Form
Powered by GitBook
On this page
  • Form validation notification
  • Service notifications
  • Backoffice entry rendering events

Was this helpful?

Edit on GitHub
Export as PDF
  1. Developer
  2. Extending

Adding A Server-Side Notification Handler To Umbraco Forms

See an example of validating a form server-side

Form validation notification

Add a new class to your project as a handler for the FormValidateNotification notification:

using System.Linq;
using Microsoft.AspNetCore.Http;
using Umbraco.Cms.Core.Events;
using Umbraco.Forms.Core.Models;
using Umbraco.Forms.Core.Services.Notifications;

namespace MyFormsExtensions
{
    /// <summary>
    /// Catch form submissions before being saved and perform custom validation.
    /// </summary>
    public class FormValidateNotificationHandler : INotificationHandler<FormValidateNotification>
    {
        public void Handle(FormValidateNotification notification)
        {
            // If needed, be selective about which form submissions you affect.
            if (notification.Form.Name == "Form Name")
            {
                // Check the ModelState
                if (notification.ModelState.IsValid == false)
                {
                    return;
                }

                // A sample validation
                var email = GetPostFieldValue(notification.Form, notification.Context, "email");
                var emailConfirm = GetPostFieldValue(notification.Form, notification.Context, "verifyEmail");

                // If the validation fails, return a ModelError
                if (email.ToLower() != emailConfirm.ToLower())
                {
                    notification.ModelState.AddModelError(GetPostField(notification.Form, "verifyEmail").Id.ToString(), "Email does not match");
                }
            }
        }

        private static string GetPostFieldValue(Form form, HttpContext context, string key)
        {
            Field field = GetPostField(form, key);
            if (field == null)
            {
                return string.Empty;
            }


            return context.Request.HasFormContentType &&  context.Request.Form.Keys.Contains(field.Id.ToString())
                ? context.Request.Form[field.Id.ToString()].ToString().Trim()
                : string.Empty;
        }

        private static Field GetPostField(Form form, string key) => form.AllFields.SingleOrDefault(f => f.Alias == key);
    }
}

The handler will check the ModelState and Form field values provided in the notification. If validation fails, we add a ModelError.

To register the handler, add the following code into the startup pipeline. In this example, the registration is implemented as an extension method to IUmbracoBuilder and should be called from Program.cs:

public static IUmbracoBuilder AddUmbracoFormsCoreProviders(this IUmbracoBuilder builder)
{
    builder.AddNotificationHandler<FormValidateNotification, FormValidateNotificationHandler>();
}

Service notifications

The services available via interfaces IFormService, IFolderService, IDataSourceService and IPrevalueSourceService trigger following notifications before or after an entity handled by the service is modified.

The "-ing" events allow for the entity being changed to be modified before the operation takes place, or to cancel the operation. The "-ed" events fire after the update is complete.

Both can be wired up using a composer and component:

    public class TestSiteComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.AddNotificationHandler<FormSavingNotification, FormSavingNotificationHandler>();
        }
    }

    public class FormSavingNotificationHandler : INotificationHandler<FormSavingNotification>
    {
        public void Handle(FormSavingNotification notification)
        {
            foreach (Form form in notification.SavedEntities)
            {
                foreach (Page page in form.Pages)
                {
                    foreach (FieldSet fieldset in page.FieldSets)
                    {
                        foreach (FieldsetContainer fieldsetContainer in fieldset.Containers)
                        {
                            foreach (Field field in fieldsetContainer.Fields)
                            {
                                field.Caption += " (updated)";
                            }
                        }
                    }
                }
            }
        }
    }

When a form or folder is moved there is no specific service event. However, information available in the State dictionary on the notification object can be used to determine whether the item was moved. If so, it can show where it was moved from:

    public class TestSiteComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.AddNotificationHandler<FormSavingNotification, FormSavingNotificationHandler>();
        }
    }

    public class FormSavingNotificationHandler : INotificationHandler<FormSavingNotification>
    {
        private readonly ILogger<FormSavingNotification> _logger;

        public FormSavingNotificationHandler(ILogger<FormSavingNotification> logger) => _logger = logger;

        public void Handle(FormSavingNotification notification)
        {
            foreach (Form savedEntity in notification.SavedEntities)
            {
                _logger.LogInformation($"Form updated. New parent: {savedEntity.FolderId}. Old parent: {notification.State["MovedFromFolderId"]}");
            }
        }
    }

If a folder is being moved, the key within the State dictionary is "MovedFromParentId".

Backoffice entry rendering events

When an entry for a form is rendered in the backoffice, an event is available to allow modification of the record detail. This event is available before the record details are presented to the user. This is shown in the following example:

    public class TestSiteComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.AddNotificationHandler<EntrySearchResultFetchingNotification, EntrySearchResultFetchingNotificationHandler>();
        }
    }

    public class EntrySearchResultFetchingNotificationHandler : INotificationHandler<EntrySearchResultFetchingNotification>
    {
        public void Handle(EntrySearchResultFetchingNotification notification)
        {
            var transformedFields = new List<object>();
            foreach (var field in notification.EntrySearchResult.Fields)
            {
                if (field?.ToString() == "Test")
                {
                    transformedFields.Add("Test (updated)");
                }
                else
                {
                    transformedFields.Add(field);
                }
            }

            notification.EntrySearchResult.Fields = transformedFields;
        }
    }
PreviousAdding a Magic String Format FunctionNextAdding a Validation Pattern

Last updated 5 months ago

Was this helpful?