Form builder development in ASP.NET Core

Form builder development under ASP.NET Core is for the most part identical to its MVC 5 counterpart. This page focuses on the small differences you need to keep in mind when developing form builder components for Core projects. For an overview of the form builder and all its features, refer to the main Form builder documentation. 

On this page, you can find information about:

Configuring the File uploader component

Limiting the maximum uploadable file size

You can control the maximum size of files uploadable via the file uploader form component by setting the FormBuilderOptions.FileUploaderFileSizeLimit option. The component will automatically prevent people from uploading files larger than the specified limit and notify them using a JavaScript notification.

using Kentico.Forms.Web.Mvc;

public void ConfigureServices(IServiceCollection services)
{
	...	

	// Sets the maximum file size of files uploaded using the 'File uploader' form component to 100MB
    // You can also load this value from any configuration source using the configuration provider pattern 
    services.Configure<FormBuilderOptions>(options => options.FileUploaderFileSizeLimit = 1024 * 100);
};

If the option is not configured, the default upload limit is set to 30 MB.

Limiting the maximum size of the uploaded files folder on the filesystem

To expedite the form submission process, all files selected using the File uploader component are immediately uploaded and stored in a dedicated folder on the server. This occurs independently of the form submission process. After the form is submitted, the system moves the corresponding file (currently selected in the File uploader component) to the folder used to store form data on the server.

As a measure of protection against denial of service attacks, for example, by repeatedly uploading large files without submitting the form, the system limits the size of the temporary folder used to store the uploaded files. The folder size limit, set to 500 MB by default, can be configured by setting the FormBuilderOptions.TemporaryUploadFilesFolderSizeLimit option. If the folder size limit is exceeded, the system prevents users from uploading additional files and logs an exception to the event log.

using Kentico.Forms.Web.Mvc;

public void ConfigureServices(IServiceCollection services)
{
	...	

	// Sets the temporary folder size limit to 1000MB
    // You can also load this value from any configuration source using the configuration provider pattern 
    services.Configure<FormBuilderOptions>(options => options.TemporaryUploadFilesFolderSizeLimit = 1000);
};

The system deletes the contents of the temporary folder once every 2 hours using the Delete old temporary upload files scheduled task (which runs via the administration project). If you wish to modify this behavior, for example in cases where you expect higher volumes of form submissions containing large files, you can override the default two-hour interval by configuring the CMSDeleteTemporaryUploadFilesOlderThan setting key in the <appSettings> section of the administration project's web.config file.

<!-- Sets the folder cleanup period to one hour -->
<add key="CMSDeleteTemporaryUploadFilesOlderThan" value="1" />

Developing custom form layouts

The layout of forms composed via the Xperience form builder is based on elements called sections. Each form section defines a block of HTML code containing one or more zones. These zones can then hold any number of form fields (based on form components).

When developing form sections under ASP.NET Core, use the HtmlHelper.Kentico().FormZoneAsync() extension method to place zones into your section's markup. Alternatively, you can use the equivalent <form-zone /> Tag Helper element.

MyFormSection.cshtml
@using Kentico.Web.Mvc
@using Kentico.Forms.Web.Mvc 

<div>
    <div style="float:left; width:50%;">
        @await Html.Kentico().FormZoneAsync()
    </div>
    <div style="float:left; width:50%;">
        @await Html.Kentico().FormZoneAsync() 
    </div>
    <div style="clear:both;" />
</div>

Registering form sections

Register sections by adding the RegisterFormSection assembly attribute to the controller class. Specify the following attribute parameters:

  • Identifier – string identifier of the form section. We recommend using sufficiently unique identifiers to avoid potential conflicts with other third-party sections, for example using a company name prefix.
  • Name – the name of the form section. Displayed when selecting sections on the Form builder tab in the administration interface.
  • CustomViewName – specifies the name and location of the view that defines the section's output. If not set, the system searches for a corresponding _<Identifier>.cshtml view in the ~/Views/Shared/Sections folder.
  • (Optional) Description – a description of the form section. Displayed as a tooltip when selecting sections on the Form builder tab in the administration interface.
  • (Optional) IconClass – the font-icon assigned to the form section. Displayed when selecting sections on the Form builder tab in the administration interface. For a list of font icons available by default in the system, see the Icon list.
[assembly: RegisterFormSection("MyCompany.FormSections.TwoColumns", "Form section name", customViewName : "~/Components/FormSections/MySection/_MySection.cshtml", Description = "My form section description.", IconClass = "icon-l-cols-2")]

The section is now available in the form builder interface.

Adding scripts and styles for form components and form sections

To add JavaScript and CSS styles required by your components, we recommend placing script and stylesheet files into sub-folders under:

  • ~/wwwroot/PageBuilder/Public/ – scripts intended for both the live site and administration. Styles intended for the live site.
  • ~/wwwroot/PageBuilder/Admin/ – scripts and styles intended for the administration interface. Note that the system already attempts to enforce a unified look and feel for components rendered in the form builder interface. See Developing form components and the GetEditorHtmlAttributes extension method.

You can use sub-folders that match the identifiers of individual components, or a Shared sub-folder for assets used by multiple components. Note that this recommendation only applies when using the default configuration of the bundling support provided by Xperience and may be different for your project. See Bundling static assets of builder components.

CSS notes

  • Only use the specified directories to add basic styles that are required for the widget to render correctly. Any site-specific styles that finalize the live site design of the widget should be handled separately within the given site's main stylesheet.
  • To avoid potential conflicts between styles from other third-party components, we recommend adding a unique prefix to your CSS classes and identifiers (e.g., #CompanyName-mid-button), or use similar measures to ensure their uniqueness.

Initializing component scripts

In many cases, you will need to initialize your scripts from the views of form components (for example if you need to call a function on page load or register an event listener). For most types of page or element events, you can use HTML Event Attributes of elements in your views.

For scripts that you want to run on page load, you need to consider the following:

  • The bundles containing your main scripts are added at the end of the HTML document's body tag, so they are not available in the component code during the page load process. A solution is to run the initialization script during the DOMContentLoaded event.
  • Components may be added dynamically after the page is loaded. In this case, the DOMContentLoaded event has already occurred and will not fire again.

For example, the following script demonstrates how to reliably call a custom function on page load:

if (document.readyState === "loading") {
    // Calls the function during the 'DOMContentLoaded' event, after the HTML document has been completely loaded
    document.addEventListener("DOMContentLoaded", function () {
        customFunction();
    });
} else { 
    // Calls the function directly in cases where the component is rendered dynamically after 'DOMContentLoaded' has occurred
    customFunction();
}

This approach ensures that the initialization script runs correctly when the form component is displayed on the live site, as well as in the form builder interface.

Note: Apart from initialization code, avoid linking or executing scripts directly within form component views – this could lead to duplicated scripts for forms that contain multiple fields based on the same component, or on pages with multiple forms.


Was this page helpful?