警告:很长的问题!有很多设置可以达到我需要提出的要求。
所以,我正在开展一个小型实验项目,因为我试图找出 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)用于从服务器接收数据以进行呈现。答案 0 :(得分:1)
我没有为你准确的答案,但我想问:既然你的应用程序已经依赖于javascript,为什么不在进行ajax调用之前验证输入客户端?最佳实践是在ajax和服务器端之前验证客户端以防万一。
也许您需要创建一个单独的验证类,其中包含您可以在模型中引用的所有规则(逻辑)和相关的错误消息。
深思熟虑,抱歉缺乏真正的答案!
编辑:我认为我已经解决了实际问题。您可以考虑始终返回具有error属性的对象,该属性在输入有效时为null,但在输入无效时包含相关的错误消息。然后在你的成功处理程序中你可以只查找错误!= null并在那里获取错误数据?