В ASP.NET MVC HtmlFieldPrefix отсутствует свойство с индексатором - PullRequest
0 голосов
/ 14 июня 2019

С помощью некоторых других вопросов StackOverflow я написал помощник HTML, чтобы получить ненавязчивые атрибуты проверки для свойства:

public static IHtmlString GetUnobtrusiveValidationAttributesFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertySelector)
{
    string propertyName = html.NameFor(propertySelector).ToString();
    ModelMetadata metaData = ModelMetadata.FromLambdaExpression(propertySelector, html.ViewData);

    //If the attributes were already generated, remove this flag so they can be generated again. Otherwise GetUnobtrusiveValidationAttributes returns empty
    html.ViewContext.FormContext.RenderedField(propertyName, false);

    var attributeCollection = html.GetUnobtrusiveValidationAttributes(metaData.PropertyName, metaData);

    return html.Raw(String.Join(" ", attributeCollection.Select(kvp => kvp.Key + "=\"" + kvp.Value.ToString() + "\"")));
}

Казалось, работает правильно. Обратите внимание, что закомментированная строка, по-видимому, была необходима при создании атрибутов для одного и того же поля более одного раза. Это связано с тем, что после однократного вызова GetUnobtrusiveValidationAttributes полное имя свойства добавляется в личный словарь HtmlHelper ViewContext.FormContext._renderedFields со значением true. Таким образом, моя закомментированная строка сначала устанавливает значение false, а затем снова возвращает атрибуты.

Проблема в том, что это не работает для моего текущего использования, на мой взгляд, который находится в цикле. Я думаю, что это будет легче всего объяснить, указав имена свойств. Первый раз это называется propertyName = "vm.CampPassPricePlans.CampPassPacks[0].SelectedCampPassExpirationRuleID". Итак, как вы можете видеть, свойство находится на первом элементе в свойстве CampPassPacks, которое является List<t>. В следующий раз, propertyName = "vm.CampPassPricePlans.CampPassPacks[1].SelectedCampPassExpirationRuleID", но GetUnobtrusiveValidationAttributes возвращает пустой результат, несмотря на то, что для этого свойства для RenderedFields установлено значение false.

Полагаю, проблема в том, что после того, как я в первый раз вызываю GetUnobtrusiveValidationAttributes, он добавляет неправильное имя свойства во внутренний словарь _renderedFields. Вместо добавления "vm.CampPassPricePlans.CampPassPacks[0].SelectedCampPassExpirationRuleID" он имеет только "vm.CampPassPricePlans.SelectedCampPassExpirationRuleID". Таким образом, он конвертирует их всех в одно и то же имя. Я подозреваю, что это потому, что html.ViewData.TemplateInfo.HtmlFieldPrefix равен только "vm.CampPassPricePlans" - он не включает сегмент или индексатор свойства CampPassPacks.

т.е. html.ViewData.TemplateInfo.HtmlFieldPrefix + "." + metaData.PropertyName! = propertyName.

Почему HtmlFieldPrefix не включает полный префикс и как это можно решить?


EDIT

Я посмотрел на GetUnobtrusiveValidationAttributes исходный код, и вот что он использует:

string fullName = html.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

где name - имя свойства, которое я передал.


TL; DR

Почему:

html.NameFor(propertySelector).ToString();

возврат "vm.CampPassPricePlans.CampPassPacks[0].SelectedCampPassExpirationRuleID"

но

html.ViewData.TemplateInfo.GetFullHtmlFieldName("SelectedCampPassExpirationRuleID")

возврат "vm.CampPassPricePlans.SelectedCampPassExpirationRuleID"?

...