Trying to get DisplayTemplates in ASP.Net Core 2.2 to work with classes that inherit from a base class similar to this question How to handle an entity model with inheritance in a view?
The Principal DisplayTemplate is being used for all items in the list, what am I missing?
PageModel
public class IndexModel : PageModel
{
public List<Principal> Principals { get; set; } = new List<Principal>();
public void OnGet()
{
Principals.Add(new Principal { Id = 1, Name = "Principal 1" });
Principals.Add(new UserPrincipal { Id = 1, Name = "User 1", Age = 30 });
Principals.Add(new GroupPrincipal { Id = 1, Name = "Group 1", Members = 5 });
Principals.Add(new UserPrincipal { Id = 1, Name = "User 2", Age = 40 });
Principals.Add(new GroupPrincipal { Id = 1, Name = "Group 2", Members = 3 });
}
}
public class Principal
{
public int Id { get; set; }
public string Name { get; set; }
}
public class UserPrincipal : Principal
{
public int Age { get; set; }
}
public class GroupPrincipal : Principal
{
public int Members { get; set; }
}
RazorPage
@page
@model IndexModel
@foreach(var principal in Model.Principals)
{
@Html.DisplayFor(p => principal)
}
~/Pages/Shared/DisplayTemplates/Principal.cshtml
@model Principal
<div>
<h4>Principal</h4>
@Model.Name
</div>
~/Pages/Shared/DisplayTemplates/UserPrincipal.cshtml
@model UserPrincipal
<div>
<h4>User</h4>
@Model.Name, Age @Model.Age
</div>
~/Pages/Shared/DisplayTemplates/GroupPrincipal.cshtml
@model GroupPrincipal
<div>
<h4>Group</h4>
@Model.Name, Members @Model.Members
</div>

The reason
That's because the expression in
@Html.DisplayFor(expression)won't be executed at all. They are parsed statically instead.For example, if we have an expression
m.a.b.cwhereaisnullat runtime, the@Html.DisplayFor(m => m.a.b.c)is still able to know the template forc.Since you're declaring the
Principalsas typeList<Principal>, even if you make theModel.PrincipalsholdUserPrincipalorGroupPrincipalat runtime, the "parser" still treat theprincipalas a basePrincipaltype: They don't inspect the real type of instance. They just parse the type statically.How to fix
Pass a template name when invoking
Html.DisplayFor()so that the Html Helper knows the real template you want to use:@page @model IndexModel @foreach (var principal in Model.Principals) { @Html.DisplayFor(p => principal, principal.GetType().Name) }Demo