Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.Net核心MVC-Ajax表单提交,在少数ViewModel属性上进行ModelState验证_C#_Ajax_Validation_Asp.net Core Mvc - Fatal编程技术网

C# ASP.Net核心MVC-Ajax表单提交,在少数ViewModel属性上进行ModelState验证

C# ASP.Net核心MVC-Ajax表单提交,在少数ViewModel属性上进行ModelState验证,c#,ajax,validation,asp.net-core-mvc,C#,Ajax,Validation,Asp.net Core Mvc,问题 我有一个具有一些必需属性和非必需属性的客户机视图模型。视图包含用于更新不同视图模型属性的不同部分。如果我正在使用所需的客户端详细信息(如FirstName、LastName、DOB等)更新视图的一部分,那么我可以将输入类型包装到ajax表单中,控制器将从视图模型中提取这些属性,并使用ModelState.IsValid进行相应的验证,验证将成功。但是,如果同一视图上有另一个部分需要更新viewmodel(ie Notes)上的非必需属性,并从ajax表单post传递该属性,那么ModelS

问题

我有一个具有一些必需属性和非必需属性的客户机视图模型。视图包含用于更新不同视图模型属性的不同部分。如果我正在使用所需的客户端详细信息(如FirstName、LastName、DOB等)更新视图的一部分,那么我可以将输入类型包装到ajax表单中,控制器将从视图模型中提取这些属性,并使用ModelState.IsValid进行相应的验证,验证将成功。但是,如果同一视图上有另一个部分需要更新viewmodel(ie Notes)上的非必需属性,并从ajax表单post传递该属性,那么ModelState验证将失败,因为其他必需属性为null,因为它们从未作为ajax表单的一部分提交。请注意,在加载客户端详细信息页面之前,必填字段应始终填充数据,因此不应为空

代码

视图模型

看法

问题

  • 如何在控制器内部高效地对某些字段执行ModelState验证,而不复制代码?我搜索了这个问题,发现了ModelState[].Errors.Clear()等选项;但由于这将是一个大视图,有许多不同的部分可供更新,我希望避免在我需要执行的所有小ajax帖子中以不同的操作方法重复这些语句。基本上,我希望使用ModelState验证,这样我就可以将验证逻辑存储在ViewModel中,而不会在控制器中分离和/或复制任何验证逻辑

  • 我可以看到的另一个选择是在我拥有的每个ajax表单中包含所有必需的属性作为隐藏的输入类型,但这似乎是非常不必要的,而且维护起来肯定是一场噩梦。是否有更好的方法来传递ajax帖子的所有ViewModel属性?如果有,发送除利用ModelState.IsValid检查之外未使用的ViewModel属性是否会很昂贵

  • 我是asp.net新手,从asp.net core mvc开始学习(我很喜欢它),一直在通过所有教程学习,所以问题,等等。但是,我是否可能以错误的方式处理此问题?如果是,使用asp.net core和Microsoft.jQuery.Unobtrusive.Ajax或其他Ajax工具解决此问题的正确方式是什么?请注意,我只是发布了这个问题,因为发布的其他类似问题似乎都不涉及在视图上共享ViewModel属性,而只是提交了一些属性,但利用了开箱即用的验证


  • 提前感谢。

    将所有呼叫的所有内容发送回并不昂贵(通过使用隐藏字段),但这是一种黑客行为,不是一种直接的解决方案

    MVC中的视图模型不必是用于呈现页面和提交表单的同一类。在您的情况下,可以定义viewmodel进行如下渲染:

    public class ClientDetailViewModel {
        public ClientBasicViewModel Basics {get;set;}
        public ClientNotesViewModel Notes {get;set;}
    }
    
    然后将字段(姓名、性别等)分别放入两个新类中。使用两个单独的控制器方法来处理表单提交。跟踪FirstName的发送和接收方式:

    • 渲染时,将使用Model.Basics.FirstName显示现有值
    • 对于表单中的字段名,将其设置为
      input name=“FirstName”…
    • 返回表单时,控制器方法接受ClientBasicViewModel类型的参数

    尽管我无法获得建议的方法,但我确实使用了关于分离视图模型以进行渲染和提交的建议。我想我是被微软ASP.NET核心网站上的电影教程引入歧途的,它在细节和编辑页面上使用相同的电影模型

    为了进一步解决我的问题,我为详细信息页面采用了一个大视图模型,我将为需要更新的页面的各个部分使用视图组件。这允许我为每个视图组件拥有一个单独的视图模型,并且我的控制器post操作可以只接受与相应视图组件相关的视图模型,因此它只能执行必要的ModelState验证

    这篇来自jQueryAjax帖子的服务器端验证已经将我引向了下一个问题,关于将ModelState错误返回给客户端以供显示,但我已经为此提交了一个新问题


    这是一个有趣的概念。我尝试按照您的建议将视图模型分解为单独的子模型,然后在我的控制器上,我传入了其中一个子模型,而不是父视图模型,但属性值为空。调试可能会很麻烦。在浏览器中检查页面源,以确保表单字段名称(name属性,而不是id属性)是处理表单提交的控制器方法所期望的。
    @model MSIC.Models.ClientViewModels.ClientDetailViewModel
    @inject MSIC.Services.Custom.IGenderService GenderService;
    
    <!-- tab-pane for updating core client details -->
    <div class="tab-pane active" id="tab_1">
        <form asp-controller="Client" asp-action="Edit" class="form-horizontal">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="FirstName" class="col-sm-2 control-label"></label>
                <div class="col-sm-10">
                    <input asp-for="FirstName" class="form-control" />
                    <span asp-validation-for="FirstName" class="text-danger" />
                </div>
            </div>
            <div class="form-group">
                <label asp-for="LastName" class="col-sm-2 control-label"></label>
                <div class="col-sm-10">
                    <input asp-for="LastName" class="form-control" />
                    <span asp-validation-for="LastName" class="text-danger" />
                </div>
            </div>
            <div class="form-group">
                <label asp-for="DOB" class="col-sm-2 control-label"></label>
                <div class="col-sm-10">
                    <input asp-for="DOB" class="form-control" />
                    <span asp-validation-for="DOB" class="text-danger" />
                </div>
            </div>
            <div class="form-group">
                <label asp-for="Gender" class="col-sm-2 control-label"></label>
                <div class="col-sm-10">
                    <select asp-for="Gender" asp-items="@(new SelectList(GenderService.GetAll(),"Code","Name"))" class="form-control">
                    </select>
                    <span asp-validation-for="Gender" class="text-danger" />
                </div>
            </div>
        </form>
    </div>
    
    <!-- different section for updating client notes -->
    <div id="divNotes" class="center-block">@Model.Notes</div>
    <a href="#" class="btn btn-danger btn-block" data-toggle="modal" data-target="#notesModal" role="button"><b>Edit Notes</b></a>
    <form asp-controller="Client" asp-action="EditNotes" class="form-horizontal" data-ajax="true" data-ajax-method="POST" data-ajax-update="#divNotes" data-ajax-mode="replace" data-ajax-success="CloseModal('#notesModal')" data-ajax-failure="AjaxOnFailure(xhr, status, error)">
        <div class="modal fade" id="notesModal" tabindex="-1" role="dialog" aria-labelledby="notesModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                        <h4 class="modal-title" id="notesModalLabel">edit Reason</h4>
                    </div>
                    <div class="modal-body">
                        <input type="hidden" asp-for="ID" />
                        <div class="form-group">
                            <div class="col-sm-10">
                                <textarea asp-for="Notes" class="form-control" autofocus></textarea>
                                <span asp-validation-for="Notes" class="text-danger" />
                            </div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <div class="text-danger pull-left">
                            <i id="modalErrorIcon" class=""></i>
                            <span id="modalErrorText"></span>
                        </div>
                        <button type="submit" class="btn btn-primary">Save</button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                    </div>
                </div>
            </div>
        </div>
    </form>
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult EditNotes(ClientDetailViewModel model)
    {
        //validation fails because required fields in model are null since they were not submitted with this ajax form
        if (ModelState.IsValid)
        {
            //update database with client notes and return notes to screen
            return Content(model.Notes);
        }
    
        return Content("i haven't coded this yet");
    }
    
    public class ClientDetailViewModel {
        public ClientBasicViewModel Basics {get;set;}
        public ClientNotesViewModel Notes {get;set;}
    }