2

我有 Asp Mvc3 应用程序。在我看来,我正在使用 kendoui + knockoutjs。我正在使用剑道验证器处理客户端验证。我对 asp mvc3 很陌生,我无法让我的服务器端验证工作。

这是我的业务对象:

[Validator(typeof(FranchiseInfoValidator))]
    public class FranchiseInfo
    {
        public string FullName { get; set; }
        public string ShortName { get; set; }
    }
}

我正在使用 FluentValidation。这是我的验证规则的实现:

public class FranchiseInfoValidator : AbstractValidator<FranchiseInfo>
    {
        public FranchiseInfoValidator()
        {
            RuleFor(franchiseInfo => franchiseInfo.FullName).NotEmpty();
            RuleFor(franchiseInfo => franchiseInfo.ShortName).NotEmpty();
        }
    }

这是我的视图模型:

public class FranchiseInfoViewModel
    {
        public string FullName { get; set; }
        public string ShortName { get; set; }
    }

这是我对 FranchiseInfoViewModel 的强类型视图:

@model MvcApplication2.Models.FranchiseInfoViewModel

<script src="../../Scripts/Details.js" type="text/javascript"></script>

<form id="franchiseForm" action="" style="font-family: Trebuchet MS, Verdana, Helvetica, Sans-Serif;"> 
     <table>
            <tr>
                <td><label for="fullName">FullName:</label></td>
                <td><input id="fullName" data-bind= "value: FullName" /></td>
            </tr>
            <tr>
                <td><label for="shortName">ShortName:</label></td>
                <td><input id="shortName" data-bind= "value: shortName" /></td>
            </tr>
    </table>
    <button id="submit" class="k-button" data-bind="click: save" form="franchiseForm">Save Franchise</button>
</form>

在提交表单时,我正在调用 javascript 函数保存:

$(function () {

    save = function () {

        // some logic

        $.ajax({
            url: "/franchise/SaveFranchise",
            type: "POST",
            data: { franchiseInfoViewModel: jsonData },               
            dataType: 'json',
            success: function (data, textStatus, xhr) {
                window.location.href = data.redirectToUrl;
            }
        });
    }
});

在保存时,我以 json 格式提交数据并将数据发送到 SaveFranchise 控制器:

public ActionResult SaveFranchise(string franchiseInfoViewModel)
        {
            var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);

            if (!ModelState.IsValid)
            { 
                // do some action
            }

            return View();
        }

我想要完成的是(!ModelState.IsValid)返回视图并显示流畅的验证错误消息。出于某种原因,在我的情况下 ModelState.IsValid 总是正确的。

如前所述,我对 Asp Mvc 3 非常陌生。从我读过的文章中,示例是将表单提交到有绑定的服务器(没有 javascript),并将服务器验证消息返回到视图。但是那里的视图是用 Razor 实现的,客户端验证是通过 jquery 完成的。

在我看来,我正在使用带有数据绑定( kendoui + 淘汰赛)的 javascript 视图模型。在我的情况下,我应该怎么做服务器端验证。请帮我。感谢您的时间和精力!

4

1 回答 1

5

简短的回答:

您应该在控制器操作中使用模型绑定 - 这样做可以让您使用ModelState.IsValid.

所以你的控制器动作:

public ActionResult SaveFranchise(string franchiseInfoViewModel)

..应该改为:

public ActionResult Create(FranchiseInfo franchiseInfo)

请务必以使模型绑定器能够实例化模型实例的格式发布您的表单FranchiseInfo。您可以使用 JSON 来执行此操作,但我认为如果您只使用表单上的标准action属性发布表单会更好(并且更简单)。

详细回答:

我建议的第一件事是使用 ASP.NET MVC 框架提供的模型验证,包括用于服务器端验证的模型绑定、模型状态和数据注释,以及用于客户端验证的不显眼的 javascript。这样做将为您提供一种更加DRY的实施方式,具有明确的关注点分离 (SoC)

要到达那里 - 我建议您首先开始查看 ASP.NET MVC 中的模型绑定。

“ASP.NET MVC 模型绑定的特性和缺点”中所述:

通过模型绑定,控制器操作可以专注于提供业务价值,避免浪费时间进行普通的请求映射和解析。

要看到这一点,这篇MSDN 文章对模型绑定器有一个很好的定义:

MVC 中的模型绑定器提供了一种将发布的表单值映射到 .NET Framework 类型并将类型作为参数传递给操作方法的简单方法。(...) 模型绑定器类似于类型转换器,因为它们可以将 HTTP 请求转换为传递给操作方法的对象。

有了这个抽象,您将很快看到以下签名:

public ActionResult SaveFranchise(string franchiseInfoViewModel)

..可以更改为:

public ActionResult Create(FranchiseInfo franchiseInfo)

...在这一点上,事情已经开始看起来更干净了,因为像您的自定义数据映射这样的代码:

var franchiseInfoVM = JsonConvert.DeserializeObject<FranchiseInfoViewModel>(franchiseInfoViewModel);

...可以删除。

一般来说,您不需要将表单序列化为 JSON 并发布 - 相反,您应该利用 MVC 中的模型绑定并以标准方式提交表单数据(通过使用action表单元素上的属性 - 好吧,模型binder 能够基于 JSON 绑定对象,但我想你明白我的意思..)。实际上,ASP.NET MVC 使得为模型生成表单变得非常简单——这里显示了Html.BeginForm一个使用示例。

因此,现在当您重构视图以使用一个表单来发布其数据而不将表单数据序列化为 JSON 时,您应该看看 MVC3 中的数据注释。

本例System.ComponentModel.DataAnnotations所述,.NET的命名空间...

提供了一组内置的验证属性,您可以以声明方式将其应用于任何类或属性。(...) 验证属性指定您希望对应用它们的模型属性强制执行的行为。

可用的注释之一是Required属性——它定义了一个特定的模型属性必须有一个值。还有其他几个属性,如Range, MaxLength,RegularExpression等。一些属性的示例使用如下所示:

public class Movie
{
    public int ID { get; set; }

    [Required(ErrorMessage = "Title is required")]
    public string Title { get; set; }

    [Required(ErrorMessage = "Date is required")]
    public DateTime ReleaseDate { get; set; }

    [Required(ErrorMessage = "Genre must be specified")]
    public string Genre { get; set; }

    [Required(ErrorMessage = "Price Required")]
    [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

(示例借鉴自:http ://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/adding-validation-to-the-model )

使用数据注释填充模型使您可以在提交给定表单时轻松检查模型是否有效,并且您可以在给定操作中检查所提供模型的有效性 -它在这里ModelState.IsValid被证明是有用的。

正如这篇文章中提到的:

(...) 第二个 Create 方法调用ModelState.IsValid来检查电影是否有任何验证错误。调用此方法会评估已应用于对象的任何验证属性。

所以在这一点上,您应该能够看到使用数据注释来声明模型上的约束/所需行为将允许您拥有一个简单的实现,其中逻辑在模型中定义并且可以使用ModelState.IsValid.

为了对此进行扩展,我可以告诉您一些我在 ASP.NET MVC3 中的服务器端和客户端进行模型验证的经验。

ModelState.IsValid正如您可能已经猜到的那样,在模型验证方面,我使用 ASP.NET MVC3 的最佳体验是使用数据注释以及通过不显眼的 JavaScript对服务器端验证和客户端验证的内置支持。

对于数据注释,我使用内置注释和数据注释扩展项目提供的扩展的组合。

使用 ASP.NET MVC3 对不显眼的客户端验证的支持有几个好处。

  • 首先,SoC真的很容易实现,因为模型验证逻辑只定义在一个地方——那就是它所属的模型中。
  • 其次,您可以在您的视图中获得更DRY的实现(避免重复的逻辑并获得更易于维护的代码)并让框架为您完成繁重的工作。

可以在 此处找到如何在 ASP.NET MVC3 中使用不显眼的客户端验证的示例。

但是,有时使用注释可能看起来不那么直接 - 例如,当您想要验证信用卡和文件扩展名等属性时。在这些需要对基本注释以外的替代方案进行逻辑调用的情况下,我倾向于使用数据注释扩展(除非我可以将我的应用程序定位为 .NET 4.5,例如,它添加了一系列更多属性,例如) ,FileExtensionAttribute因为它们提供了一系列开箱即用的出色注释扩展(存在用于 MVC3 的数据注释扩展 nuget 包- 因此设置和开始使用非常简单)。

还有一些特殊情况,您可能拥有取决于数据库状态的属性 - 例如,如果您想在用户填写用户注册表单时检查用户名是否已经存在。在这种情况下,ASP.NET MVC3 远程验证注释是您的朋友。正如这篇MSDN 文章所述

ASP.NET MVC 3 提供了一种机制,可以进行远程服务器调用以验证表单字段,而无需将整个表单发布到服务器。当您有一个无法在客户端上验证的字段并且因此在提交表单时可能无法通过验证时,这很有用。

ASP.NET MVC3 中远程验证的好处是,它也可以使用数据注释来表示(如这篇博文和这篇MSDN 文章中所示)。

综上所述 - 使用这些框架功能 (imo) 确实为您提供了一系列工具,可以或多或少地涵盖 ASP.NET MVC3 中“正确方式”的任何类型的模型验证。

于 2012-08-31T23:22:59.933 回答