@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
Другие вопросы по тегам