【问题标题】:Using DataAnnotations/IValidatable object on a model passed to server via AJAX call在通过 AJAX 调用传递给服务器的模型上使用 DataAnnotations/IValidatable 对象
【发布时间】:2014-04-08 19:04:37
【问题描述】:

警告:问题太长了!有很多设置可以解决我需要询问的问题。

所以,我正在做一个小型实验项目,因为我试图弄清楚 如果我可以在通过 AJAX 发送到服务器的模型上触发服务器端 MVC 验证.实验应用采用音符名称、符号和八度音阶来确定音符的频率。

我的观点很标准:

<div id='frequency-line-container'>
    // By default, nothing...
</div>

<div id='new-line-interface'>
    <p>
        What note is sounding?  <input type='text' id='note-name' maxlength='1' />
    </p>

    <p>
        What sign is by the note?

        <span>
            @Html.RadioButton("note-sign", "natural", true, new {id="note-natural"})Natural 
            @Html.RadioButton("note-sign", "sharp", false, new {id="note-sharp"})Sharp
            @Html.RadioButton("note-sign", "flat", false, new {id="note-flat"})Flat
        </span>
    <p>

    <p>
        What octave is the note sounding at?  <input type='number' id='octave' maxlength='1' min='0' max='9' />
    </p>

    <a href='#' id='save-button'>Save</a>
</div>

在客户端,我设置了以下 JavaScript:

$(document).ready(function () {
    var $frequencyLineContainer = $('#frequency-line-container'),
        $saveLineButton = $('#save-line'),
        $noteName = $('#note-name'),
        $octave = $('#octave');

    $saveLineButton.click(function (e) {
        e.preventDefault();

        var data = getLineData();
        var $promise = getNewLinePromise(data, true);
        $.when($promise)
            .then(addLine);
    });

    function getLineData() {
        var $noteSign = $('#note-sign-section input[type="radio"][name="note-sign"]:checked');
        var model = {
            'NoteName': $noteName.val(),
            'NoteSign': $noteSign.val(),
            'Octave': parseInt($octave.val())
        };

        return {
            'model': model
        };
    }

    function getNewLinePromise(data, async) {
        return $.ajax({
            type: 'POST',
            url: '/Home/AddFrequencyLine/',
            contentType: 'application/json',
            data: data,
            async: async
        });
    }

    function addLine(result) {
        $frequencyLineContainer.append(result);
    }
});

...在服务器上,我的操作非常简单:

[HttpPost]
public void AddFrequencyLine(FrequencyLineViewModel model)
{
    model.CalculateFrequency();  // Determines the frequency of a note by sign, name, and octave...
    return Partial("_FrequencyLine", model);
}

目前为止课程的标准。 现在,事情变得有趣了。

如您所见,虽然我们的笔记名称字段仅限于单个字符,但他们可以输入无效的笔记名称;音符范围从 A 到 G。如果用户从 H 到 Z 输入任何内容,则这不是有效的音符,因此不应生成频率!实际上,注释名称字段旁边应该会出现一条红色的错误消息。

我的FrequencyLineViewModel 看起来像这样...

public enum NoteSign 
{
    Natural,
    Sharp,
    Flat
}

public class FrequencyLineViewModel : IValidatableObject
{
    [Required]
    public string NoteName { get; set; }

    [Required]
    public NoteSign NoteSign { get; set; }

    [Required]
    public int Octave { get; set; }

    public Dictionary<string, float> FrequencyLookup = new Dictionary<string, float>{
        // Each note from A0 to G#0 has an associated frequency.  This lists 'em.
        // A full listing of the frequency table is not salient to this question.
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext context)
    {
        List<ValidationResult> results = new List<ValidationResult>();

        byte asciiCode = (byte) (NoteName.ToUpper())[0];
        if(asciiCode >= 72    // Between H and Z
           && asciiCode <= 90)
        {
            results.Add(new ValidationResult("(Invalid)", new []{"NoteName"}));
        }

        // Could add other validations here

        return results;
    }
}

到目前为止,在我的测试中,我已经修改了我的动作

public void AddFrequencyLine(FrequencyLineViewModel model)
{
    model.IsValid = ModelState.IsValid;
    if (ModelState.IsValid)
    {
        model.CalculateFrequency();
        return PartialView("_NoteRecord", model);
    }

    // Need to change this...but to what?
    model.ErrorMessage = "Something is wrong!";
    return model;
}

...但是我不知道如何最好地实现验证的成果。我在 model.IsValid 检查的修改操作中设置了一个断点,并发现在无效的情况下,例如空表单或来自 H-Z 的注释,它被正确标记为无效;相反,当输入有效表单时,它会按预期工作。但是,我对“正确工作”部分不感兴趣。无效状态让我受阻。

如果结果的 IsValid 属性为 false(仅在无效的代码路径上发生),我可以简单地返回错误消息,并在成功处理程序中使用 JavaScript 来确定放置它的位置。问题是,这违背了 success 处理程序的目的;真正发生的是错误状态。

所以,最后,我的问题:我正在尝试显示一些验证消息,但此设置不适合这样做。在不使用我的 JavaScript 成功处理程序的情况下,如何使这个基于 AJAX 的模型验证呈现验证消息?

编辑:这是一个问题的原因是因为我们的团队希望将尽可能多的业务逻辑保留在服务器上;我们正在努力实现“瘦客户端”设置。这意味着 JavaScript 将只负责 1) GUI 状态,2) 将数据汇集回服务器进行处理,以及 3) 从服务器接收数据以进行呈现。

【问题讨论】:

    标签: javascript jquery ajax validation asp.net-mvc-4


    【解决方案1】:

    我没有给你一个准确的答案,但我想问:既然你的应用程序已经依赖于 javascript,为什么不在进行 ajax 调用之前验证输入客户端?最佳做法是在 ajax 之前验证客户端和服务器端以防万一。

    也许您需要创建一个单独的验证类,其中包含您的所有规则(逻辑)和相关的错误消息,然后您可以在其中的模型中引用它们。

    深思,抱歉没有真正的答案!

    编辑:我想我离解决实际问题还有很长的路要走。您可以考虑始终返回一个带有错误属性的对象,该属性在输入有效时为 null,但在输入无效时包含相关错误消息。然后在您的成功处理程序中,您可以只查找错误!= null 并在那里获取错误数据?

    【讨论】:

    • 在我们的案例中,我团队的领导希望尽可能多地在服务器上保留我们的业务逻辑;我们正在努力实现“瘦客户端”设置。这意味着 JavaScript 将仅负责 1) GUI 状态,2) 将数据汇集回服务器进行处理,以及 3) 从服务器接收数据以进行呈现。
    • 这是有道理的。 ajax 调用中“成功”函数的命名是否令人困惑?我认为意思不是“没有错误”,而是“我收到了这个 ajax 调用的响应”。因此在语义上没有问题。您可以返回一个带有 null 错误属性的对象,并始终在您的“成功”函数中检查它。如果 error 不为 null,则说明验证失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多