@Html.BeginCollectionItem с несоответствием IValidatableObject и MemberName
При использовании помощника @Html.BeginCollectionItem Стивена Сандерсона я пытаюсь проверить элементы коллекции на стороне сервера с помощью интерфейса IValidatableObject.
Я хочу запретить пользователю выбирать два одинаковых элемента. Так, например, учитывая список идиом, на которых говорит пользователь, можно отправить обратно эти значения:
English
English
Spanish
Validate
реализация выглядит так:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach(var idiom in Idioms)
{
if(Idioms.Any(i => i != idiom && i.Idiom == idiom.Idiom))
{
yield return new ValidationResult("Idiom already selected", new string[] { "Idiom" });
}
}
}
Проблема в том, что MemberName
("Идиома") перешел к ValidationResult
отличается от MemberName
присутствует в ModelState
словарь, так как помощник Стивен использует Guid
и выглядит так:
[42] = {[Idioms[83c2c6db-0157-42f3-bf3f-f7c9e6bc0a37].Idiom, System.Web.Mvc.ModelState]}
как вы видете Idiom != [Idioms[83c2c6db-0157-42f3-bf3f-f7c9e6bc0a37].Idiom
,
В лучшем случае я должен был бы иметь способ передать например [Idioms[83c2c6db-0157-42f3-bf3f-f7c9e6bc0a37].Idiom
как MemberName
но я не знаю, как получить эту информацию от validationContext
или даже если это вообще возможно. В любом случае это должно быть динамичным.
Знаете ли вы о каком-либо способе преодолеть это?
1 ответ
После долгих поисков я нашел правильный способ делать то, что хочу:
Проверка модели в ASP.NET MVC 3
Чтобы проверить (т.е. найти повторяющиеся записи) в свойстве коллекции / списка в вашем ViewModel
Вы должны добавить
@Html.ValidationMessageFor(u => u.Idioms)
для собственности в вашем View
и составить errorMessage
внутри Validate
метод. Наконец, присвойте сообщение правильному имени свойства, то есть Idioms
в моем случае.
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var grouping = Idioms.GroupBy(ui => ui.Idiom);
var duplicates = grouping.Where(group => group.Count() > 1);
if(duplicates.Any())
{
string message = string.Empty;
foreach(var duplicate in duplicates)
{
message += string.Format("{0} was selected {1} times", duplicate.Key, duplicate.Count());
}
yield return new ValidationResult(message, new[] { "Idioms" });
}
}
БОНУС
Если вы хотите отобразить каждую дублирующую группу в separate lines
(добавление разрывов строк <br>
), сделай это:
замещать {0} was selected {1} times
с {0} was selected {1} times<br>
а затем на View
сторона делает это:
@Html.Raw(HttpUtility.HtmlDecode(Html.ValidationMessageFor(u => u.Idioms).ToHtmlString()))
Выход будет:
French was selected 2 times
English was selected 3 times