在通过AJAX调用传递给服务器的模型上使用DataAnnotations / IValidatable对象

时间:2014-04-08 19:04:37

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

警告:很长的问题!有很多设置可以达到我需要提出的要求。

所以,我正在开展一个小型实验项目,因为我试图找出 if 我可以在通过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的注释,它正确地标记为无效;相反,当输入有效表格时,它按预期工作。但是,我对'正确的'部分感兴趣;无效的状态让我陷入困境。

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

所以,最后,我的问题:我正在尝试显示一些验证消息,但这种设置不适合这样做。如果不使用我的JavaScript成功处理程序,我该怎么做才能使这个基于AJAX的模型验证显示验证消息?

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

1 个答案:

答案 0 :(得分:1)

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

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

深思熟虑,抱歉缺乏真正的答案!

编辑:我认为我已经解决了实际问题。您可以考虑始终返回具有error属性的对象,该属性在输入有效时为null,但在输入无效时包含相关的错误消息。然后在你的成功处理程序中你可以只查找错误!= null并在那里获取错误数据?