如何在Razor Pages中使用单独的BindProperty实现两种形式?

Ing*_*mar 9 asp.net-core-2.0 razor-pages

我正在将ASP.NET Core 2与Razor页面一起使用,并且试图在一页上使用两种具有单独属性(BindProperty)的表单

@page
@model mfa.Web.Pages.TwoFormsModel
@{
    Layout = null;
}

<form method="post">
    <input asp-for="ProductName" />
    <span asp-validation-for="ProductName" class="text-danger"></span>
    <button type="submit" asp-page-handler="Product">Save product</button>
</form>

<form method="post">
    <input asp-for="MakerName" />
    <span asp-validation-for="MakerName" class="text-danger"></span>
    <button type="submit" asp-page-handler="Maker">Save maker</button>
</form>
Run Code Online (Sandbox Code Playgroud)

和对应的PageModel:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;

namespace mfa.Web.Pages
{
    public class TwoFormsModel : PageModel
    {
        [BindProperty]
        [Required]
        public string ProductName { get; set; }

        [BindProperty]
        [Required]
        public string MakerName { get; set; }

        public async Task<IActionResult> OnPostProductAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            return Page();
        }

        public async Task<IActionResult> OnPostMakerAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            return Page();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

点击两个提交按钮中的任何一个都会将我带到相应的帖子处理程序中。“ ProdutName”和“ MakerName”都用我在相应输入字段中键入的内容填充。到目前为止,一切都很好。

但是:ModelState.IsValid()始终返回true- 不管相应属性的值是否具有值。即使两个属性均为null,ModelState.IsValid()也为true。

另外:OnPostProductAsync()应该只验证“ ProductName”,因此OnPostMakerAsync()应该只验证“ MakerName”。

可以做到吗?还是我对Razor Pages的要求太多?有很多博客和教程向您展示如何在一页上具有两种形式……但是它们都使用相同的模型。我需要不同的型号!

pit*_*dis 5

为了使验证正常进行,您将必须创建一个包含两个属性的视图模型,并为要检查的每个属性定义[Required],但是由于您有两种具有不同验证方式的不同形式,因此不能正常工作,因为如果两个值均按要求定义,则当您尝试验证产品时,它也会验证没有值的制造商。

您可以做的是自己检查。例如,OnPostProduct可以具有以下代码:

public async Task<IActionResult> OnPostProductAsync()
{
    if (string.IsNullOrEmpty(ProductName))
    {
        ModelState.AddModelError("ProductName", "This field is a required field.");
        return Page();
    }

    // if you reach this point this means that you have data in ProductName in order to continue

    return Page();
}
Run Code Online (Sandbox Code Playgroud)


Avn*_*rSo 5

我的解决方案不是很优雅,但它不需要您手动进行验证。您可以保留[Required]注释。

你的PageModel意志看起来像这样 -

    private void ClearFieldErrors(Func<string, bool> predicate)
    {
        foreach (var field in ModelState)
        {
            if (field.Value.ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid)
            {
                if (predicate(field.Key))
                {
                    field.Value.ValidationState = Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Valid;
                }
            }
        }
    }

    public async Task<IActionResult> OnPostProductAsync()
    {
        ClearFieldErrors(key => key.Contains("MakerName"));
        if (!ModelState.IsValid)
        {
            return Page();
        }

        return Page();
    }

    public async Task<IActionResult> OnPostMakerAsync()
    {
        ClearFieldErrors(key => key.Contains("ProductName"));
        if (!ModelState.IsValid)
        {
            return Page();
        }

        return Page();
    }
Run Code Online (Sandbox Code Playgroud)

这不是最好的主意,因为您需要将绑定的字段名称与字符串进行比较。我使用是Contains因为字段键不一致,有时包含前缀。对我来说已经足够好了,因为我的表单很小,并且具有不同的字段名称。