DisplayTemplate игнорируется (ковариантный интерфейс?)

Это странно. У меня есть следующий файл просмотра (Views/Search/Submit.cshtml):

@model IEnumerable<KeyValuePair<string, ISearchProvider>>

@foreach (var provider in Model)
{
    var results = provider.Value.Results.Take(10);

    if (results.Count() > 0)
    {
        <text><li class="dropdown-header">@provider.Key</li></text>
        @Html.DisplayFor(x => results)   
    }
}

... где results это System.Collections.Generic.IEnumerable<out T>, а также T is ISearchMatch,

Затем я определил шаблон отображения в Views/Search/DisplayTemplates/SiteSearchMatch.cshtml;

@model SiteSearchMatch
<li>@Html.ActionLink(Model.Name, "details", "site", new { Id = Model.Id }, null)</li>

... а также SiteSearchMatch инвентарь ISearchMatch вот так;

public class SiteSearchMatch: ISearchMatch
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Я ожидаю, что мой шаблон дисплея будет использоваться; но это не так. Вместо этого вывод, который я вижу, является выводом;

<li class="dropdown-header">sites</li>
11147166811481897189813271028

... где эта строка чисел является комбинацией всех Idс ISearchMatchЯ хотел сделать с помощью шаблона отображения.

Кажется, Бритва просто делает ISearchMatch использование первого атрибута, определенного в классе; если я уберу определение Id собственность, я вместо этого вижу комбинацию всех Nameиз ISearchMatch"S.


Кто-нибудь знает, почему это происходит, и как я могу заставить Razor использовать указанный мной шаблон отображения?

2 ответа

Решение

Хромой ответ - "Действие по сборке" в моем файле View Views/Search/DisplayTemplates/SiteSearchMatch.cshtml было установлено "Нет", а не "Содержимое".

Это означало, что код работал нормально при запуске в режиме отладки в Visual Studio, но не работал при любом развертывании.

Просто чтобы повторить; это исправление не требовало изменений кода. Просто измените "Build Action" обратно на "Content".

Ваше ожидание неверно:

Я ожидаю, что мой шаблон дисплея будет использоваться; но это не так.

Вывод, который вы видите, это просто ID. Я подозреваю, что ваш ISearchMatch-интерфейс только выставляет Id-свойства, но это не имеет значения. Важным является фактический тип экземпляра результата. В вашем случае следующая строка:

@Html.DisplayFor(x => results)

может быть неявно оценено как

HtmlHelper<IEnumerable<KeyValuePair<string, ISearchProvider>>>
    .DisplayFor<IEnumerable<KeyValuePair<string, ISearchProvider>>, IEnumerable<ISiteMatch>>
        (Func<IEnumerable<KeyValuePair<string, ISearchProvider>>, IEnumerable<ISiteMatch>> expression);

Выглядит довольно сложно, но в основном это просто неявная замена вашей модели и результата выражения. Ваша модель имеет тип IEnumerable<KeyValuePair<string, ISearchProvider>>, Это также тип ввода вашего лампда-выражения. Результат имеет тип IEnumerable<ISiteMatch>, И здесь самое главное!

DisplayFor реализация проверяет, является ли тип результата перечислимым или нет. Если нет, он ищет подходящий шаблон для типа, в противном случае он будет перебирать элементы и делает это для всех элементов. 1

Поиск шаблона работает на основе имени типа. В вашем случае шаблон использует имя перечисляемого типа, которое ISearchMatch, Он не находит шаблон отображения, поэтому просто выводит свойства, в результате чего вы видите:

11147166811481897189813271028

Чтобы решить эту проблему, вам нужно сначала преобразовать набор результатов в правильный тип. Вы можете сделать это по-разному. Либо вы разыгрываете весь результат результатов вашего провайдера:

var results = provider.Value.Results
    .Cast<SiteSearchMatch>()
    .Take(10);

или вы произносите их индивидуально в своем выражении ламда:

@Html.DisplayFor(x => (SiteSearchMatch)results)

Важно то, что скалярный тип результата совпадает с моделью в вашем шаблоне отображения.

1 Обратите внимание, что это немного сложнее, например, расширение также отслеживает индекс и применяет его к выходным данным, чтобы модель могла быть привязана для целей обратной передачи.

Другие вопросы по тегам