I'm playing with ASP.NET Core and trying to come up with a UI for a simple word game. You receive a randomly generated long word, and you're expected to submit shorter words from letters provided by the long word.
The application doesn't use a repository of any kind yet, and it simply stores a model instance as a static field in the controller for now.
I'm currently facing a problem where every time a new submitted word is validated, a new game instance is created, which naturally guarantees to render a validation error, because each game provides a new long word.
I must be misunderstanding something about the way model validation works but debugging doesn't give me any better clues than just showing a validation context that comes in with a new long word every time.
I'm stuck, please help.
Here's the 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);
}
}
Game 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));
}
}
A custom validation attribute where validation fails:
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");
}
}
View:
@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>
Thanks.