我正在玩 ASP.NET Core 并尝试为简单的文字游戏设计一个 UI。您会收到一个随机生成的长词,您需要根据长词提供的字母提交较短的词。
该应用程序还没有使用任何类型的存储库,它现在只是将模型实例作为静态字段存储在 Controller 中。
我目前面临一个问题,每次验证新提交的单词时,都会创建一个新的游戏实例,这自然会保证呈现验证错误,因为每个游戏都提供了一个新的长单词。
我一定是误解了模型验证的工作方式,但调试并没有给我任何比每次都显示一个新的长单词的验证上下文更好的线索。
我卡住了,请帮忙。
这是 Controller :
public class HomeController : Controller
{
private static WordGameModel _model;
public IActionResult Index()
{
if (_model == null)
{
_model = new WordGameModel();
}
return View(_model);
}
[HttpPost]
public IActionResult Index(WordGameModel incomingModel)
{
if (ModelState.IsValid)
{
_model.Words.Add(incomingModel.ContainedWordCandidate);
return RedirectToAction(nameof(Index), _model);
}
return View(_model);
}
}
游戏模型:
public class WordGameModel
{
public WordGameModel()
{
if (DictionaryModel.Dictionary == null) DictionaryModel.LoadDictionary();
LongWord = DictionaryModel.GetRandomLongWord();
Words = new List<string>();
}
public string LongWord { get; set; }
public List<string> Words { get; set; }
[Required(ErrorMessage = "Empty word is not allowed")]
[MinLength(5, ErrorMessage = "A word shouldn't be shorter than 5 characters")]
[MatchesLettersInLongWord]
[NotSubmittedPreviously]
public string ContainedWordCandidate { get; set; }
public bool WordWasNotSubmittedPreviously() => !Words.Contains(ContainedWordCandidate);
public bool WordMatchesLettersInLongWord()
{
if (string.IsNullOrWhiteSpace(ContainedWordCandidate)) return false;
return ContainedWordCandidate.All(letter => LongWord.Contains(letter));
}
}
验证失败的自定义验证属性:
internal class MatchesLettersInLongWord : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
WordGameModel model = (WordGameModel) validationContext.ObjectInstance;
if (model.WordMatchesLettersInLongWord()) return ValidationResult.Success;
return new ValidationResult("The submitted word contains characters that the long word doesn't contain");
}
}
查看:
@model WordGameModel
<div class="row">
<div class="col-md-12">
<h2>@Model.LongWord</h2>
</div>
</div>
<div class="row">
<div class="col-md-6">
<form id="wordForm" method="post">
<div>
<input id="wordInput" asp-for="ContainedWordCandidate"/>
<input type="submit" name="Add" value="Add"/>
<span asp-validation-for="ContainedWordCandidate"></span>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-6">
<ul>
@foreach (var word in @Model.Words)
{
<li>@word</li>
}
</ul>
</div>
</div>
谢谢。
最佳答案
您的 View 需要为 LongWord
包含一个隐藏输入,以便在 POST 方法中,以便在 ModelBinder 调用您的构造函数后,设置 LongWord
基于表单值(即您发送到 View 的值)
<form id="wordForm" method="post">
<div>
<input type="hidden" asp-for="LongWord" /> // add hidden input
<input id="wordInput" asp-for="ContainedWordCandidate"/>
<input type="submit" name="Add" value="Add"/>
<span asp-validation-for="ContainedWordCandidate"></span>
</div>
</form>
作为旁注,在您的 post 方法中,它应该只是 return RedirectToAction(nameof(Index));
- GET 方法没有(也不应该)有模型参数,所以传递它是没有意义的(而且它只会创建一个丑陋的查询字符串)
关于c# - ASP.NET Core 自定义验证创建模型的新实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52994266/