如何为部分视图中的元素实现验证规则

How to implement validation rules for elements from a partial view

我们正在开发 .net core 3.1 MVC 应用程序(实际使用 MVVMC)。

我们已经实现了自定义验证属性。并希望在服务器和客户端检查它们。

该视图是标准视图,但用户可以向标准视图添加多个局部视图(通过按钮)。

在部分视图中,我们无法在输入字段中使用 'asp-for' 标签助手,因为可以多次添加相同的项目,我们需要能够在其中创建一个列表从那些额外的部分视图中选择的 ViewModel。这就是我们尝试自己构建标签的原因。

一旦通过 ajax 请求了部分视图,我们将再次调用验证器。服务器验证有效,客户端验证仅适用于主视图上的那些输入,不适用于部分视图上的输入。但是,刷新后或服务器在验证错误后将用户发回时,客户端验证开始工作(因为站点已完全刷新并且 jquery 验证考虑了部分视图的输入字段)。

请查找以下代码:

验证属性的实现

public class AllowedExtensionsAttribute: ValidationAttribute, IClientModelValidator
{
    private readonly List<string> _extensions = new List<string>();

    public AllowedExtensionsAttribute(string extensions)
    {
        _extensions.Add(extensions);
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        if (value is IFormFile file)
        {
            var extension = Path.GetExtension(file.FileName);

            if (!_extensions.Contains(extension.ToLower()))
            {
                return new ValidationResult(ErrorMessage);
            }
        }

        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        context.Attributes.Add("data-val", "true");
        context.Attributes.Add("data-val-extension", ErrorMessage);
    }
 

}

MainViewModel

[AllowedExtensions(".pdf", ErrorMessage = "This data type is not allowed!")]
public IFormFile PdfDocumentOne { get; set; }

PartialViewModel

[AllowedExtensions(".pdf", ErrorMessage = "This data type is not allowed!")]
public IFormFile PdfDocumentTwo { get; set; }

主视图

<form method="post" asp-controller="Home" asp-action="MainView" enctype="multipart/form-data">
    <div class="form-group top-buffer">
        <div class="row">
            <div class="col-2">
                <label asp-for="PdfDocumentOne" class="control-label"></label>
            </div>
            <div class="col-3">
                <input asp-for="PdfDocumentOne" class="form-control-file" accept="application/pdf" />
                <span asp-validation-for="PdfDocumentOne" class="text-danger"></span>
            </div>
        </div>
    </div>
    
    
    <div id="container">
        <div id="containerFull" class="form-group">
            <div class="row">
                <div class="col-2">
                    <label class="control-label">...</label>
                </div>
                <div class="col-10">
                    <div id="containerPartialView">
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-2">
                </div>
                <div class="col-3">
                    <button id="AddPartialView" type="button" class="form-control">...</button>
                </div>
            </div>
        </div>
    </div>

    ...
    
     <div class="form-group top-buffer">
         <div class="row">
             <div class="col-2">
                 <input type="submit" value="Submit" class="form-control" id="checkBtn" />
             </div>
         </div>
     </div>
</form>

局部视图

<input id="Lists[@Model.ViewId].ViewId" name="Lists[@Model.ViewId].ViewId" class="partialViewModel" type="hidden" value="@Model.ViewId" />

<div id="Lists[@Model.ViewId].MainContainer" class="partialView">
    <div class="form-group">
        <div> 
            <div class="col-2">
                <label asp-for="PdfDocumentTwo" class="control-label"></label>
            </div>
            <div class="col-3">
                <input name="Lists[@Model.ViewId].PdfDocumentTwo" id="Lists[@Model.ViewId].PdfDocumentTwo " type="file" class="form-control-file" accept="application/pdf" 
                               data-val="true" data-val-extension="This data type is not allowed!"/>
                <span class="text-danger field-validation-valid" data-valmsg-for="Lists[@Model.ViewId].PdfDocumentTwo" data-valmsg-replace="true"></span>
            </div>
        </div>  
    </div>          
    ...
</div>

Javascript

function AddPartialView() {
    var i = $(".partialView").length;
    $.ajax({
        url: '/Home/AddPartialView?index=' + i,
        success: function (data) {
            $('#containerPartialView').append(data);
            $().rules('remove','extension');
            jQuery.validator.unobtrusive.adapters.addBool("extension");
        },
        error: function (a, b, c) {
            console.log(a, b, c);
        }
    });
}

$('#AddPartialView').click(function () {
    AddPartialView();
});

jQuery.validator.addMethod("extension",
    function (value, element, param) {

        var extension = value.split('.').pop().toLowerCase();

        if ($.inArray(extension, ['pdf']) == -1) {
            return false;
        }
        return true;
    });

jQuery.validator.unobtrusive.adapters.addBool("extension");

家庭控制器

[HttpPost]
public IActionResult MainView(MainViewModel vm)
{
    if (vm == null)
    {
        return RedirectToAction("Index");
    }

    DatabaseHelper.GetMainViewModel(vm);
        
    if (!ModelState.IsValid)
    {
        @ViewData["StatusMessageNegative"] = "The entered data is not valid. Please scroll down to correct your data.";
         return View(vm);
     }
    
     return RedirectToAction("UploadDocument", new { Id = vm.Id});
 }


 [HttpGet]
 public ActionResult AddPartialView(int index)
 {
     PartialViewModel pvm = DatabaseHelper.GetPartialViewModel(index);
     return PartialView("Partial", pvm);
 }

在网上搜索后,我们发现了以下参数(data-ajax="true")。但是,我们不知道将它放在哪里或如何正确使用它。

您是否尝试过在加载局部视图后重新应用验证?

$.ajax({
    url: '/Home/AddPartialView?index=' + i,
    success: function (data) {
        $('#containerPartialView').append(data);
        $().rules('remove','extension');
        jQuery.validator.unobtrusive.adapters.addBool("extension");
    },
    error: function (a, b, c) {
        console.log(a, b, c);
    }
}).then(function () {
$("form").each(function () { $.data($(this)[0], 'validator', false); });
$.validator.unobtrusive.parse("form");

});