如何在没有页面构建器的情况下在 Kentico 12 中使用 BizForms

How to use BizForms in Kentico 12 without page builder

Kentico 12 仅支持使用开箱即用的 "Form" 页面构建器小部件的表单。

任何人都可以提供示例说明如何在 MVC _Layout.cshtml 或不使用页面构建器的页面中使用 BizForms 吗?

验收标准:

哈迪斯, 您可以使用 Forms API (https://docs.kentico.com/api12/content-management/form-data) 来 save/access 表单数据并为其实现完全自定义的布局。 希望对您有所帮助!

您可以查看 MVC 项目中的 Kentico.Forms.Web.Mvc.Widgets 命名空间(它应该默认包含)。

其中有一个 KenticoFormWidgetController 控制器 class,它呈现部分表单并接受表单提交。您可以使用该控制器的 Index 路由来呈现您的部分表单,但我不知道该路由的具体外观。

如果您可以访问 Kentico 的源代码,您可以自己检查它的内部结构。

Form 小部件使用以下视图结构和视图模型的组合呈现 FormWidgetViewModel:

using (Ajax.Kentico().BeginForm( ... ))
{
    @Html.AntiForgeryToken()

    @Html.Kentico().FormFields(Model.FormComponents, Model.FormConfiguration, FormFieldRenderingConfiguration.Widget)

    // Render Model.SubmitButtonImage using @Html.Kentico().ImageInput( ... )
    // Or render a plain <input> using Model.SubmitButtonText
}

如果您有表单的 BizFormInfo 对象,则以下属性需要它:

new FormWidgetViewModel
{
    FormName = formInfo.FormName,
    FormConfiguration = IFormBuilderConfigurationRetriever.Retrieve(formInfo),
    FormComponents = IFormProvider.GetFormComponents(formInfo).GetDisplayedComponents( ... ),
    FormPrefix = // This may be optional outside of the Page Builder context,
    SubmitButtonText = formInfo.FormSubmitButtonText,
    SubmitButtonImage = formInfo.FormSubmitButtonImage
}

Ajax.Kentico().BeginForm 中,您可以传入控制器和处理表单的操作。

使用 IFormProvider 中的方法更新或添加表单提交以及发送电子邮件。

更新(见评论):

IFormBuilderConfigurationRetriever被标记为internal,所以不能直接访问。它的实现又使用 IFormBuilderConfigurationSerializer 来反序列化 formInfo.FormBuilderLayout。该接口也标记为 internal。此外,该接口的实现使用 internal FormBuilderTypesBinder.

这意味着没有 API 可用于检索 Model.FormConfiguration。从 Kentico 12.0.16 开始,您需要重新创建内部功能。基本实现是这样的:

JsonConvert.DeserializeObject<FormBuilderConfiguration>(formInfo.FormBuilderLayout, new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        TypeNameHandling = TypeNameHandling.Auto,
        SerializationBinder = // Set to the internal FormBuilderTypesBinder, which validates only known form builder types
        StringEscapeHandling = StringEscapeHandling.EscapeHtml
    });

OP post编辑了 blog about how to make this work

该解决方案需要使用 Kentico 的一些内部 API 来使用表单小部件呈现表单生成器并将该代码放入控制器操作中。

var formInfo = BizFormInfoProvider
    .GetBizFormInfo(formName, SiteContext.CurrentSiteName);

string className = DataClassInfoProvider
    .GetClassName(formInfo.FormClassID);

var existingBizFormItem = className is null
    ? null
    : BizFormItemProvider
        .GetItems(className)?.GetExistingItemForContact(
           formInfo, contactContext.ContactGuid);

var formComponents = formProvider
    .GetFormComponents(formInfo)
    .GetDisplayedComponents(
      ContactManagementContext.CurrentContact, 
      formInfo, existingBizFormItem, visibilityEvaluator);

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    TypeNameHandling = TypeNameHandling.Auto,
    StringEscapeHandling = StringEscapeHandling.EscapeHtml
};

var formConfiguration = JsonConvert.DeserializeObject<FormBuilderConfiguration>(
    formInfo.FormBuilderLayout, settings);

return new FormWidgetViewModel
{
    DisplayValidationErrors = true,
    FormComponents = formComponents.ToList(),
    FormConfiguration = formConfiguration,
    FormName = formName,
    FormPrefix = Guid.NewGuid().ToString(),
    IsFormSubmittable = true,
    SiteForms = new List<SelectListItem>(),
    SubmitButtonImage = formInfo.FormSubmitButtonImage,
    SubmitButtonText = string.IsNullOrEmpty(formInfo.FormSubmitButtonText) 
      ? ResHelper.GetString("general.submit")
      : ResHelper.LocalizeString(formInfo.FormSubmitButtonText)
};

我采纳了这个想法并写了一篇后续文章 post,Kentico EMS: MVC Widget Experiments Part 3 - Rendering Form Builder Forms Without Widgets,这表明我们还可以使用 Kentico 的预构建表单小部件视图代码来获得预期的呈现和表单提交功能.

<!-- ~/Views/Form/Form.cshtml -->

@using Kentico.Forms.Web.Mvc;
@using Kentico.Forms.Web.Mvc.Widgets;
@using Kentico.Forms.Web.Mvc.Widgets.Internal

@model FormWidgetViewModel

@{
    var config = FormWidgetRenderingConfiguration.Default;

    // @Html.Kentico().FormSubmitButton(Model) requires 
    // this ViewData value to be populated. Normally it
    // executes as part of the Widget rendering, but since
    // we aren't rendering a Widget, we have to do it manually

    ViewData.AddFormWidgetRenderingConfiguration(config);
}

@using (Html.Kentico().BeginForm(Model))
{
    @Html.Kentico().FormFields(Model)

    @Html.Kentico().FormSubmitButton(Model)
}