I am attempting to access the concrete implementation of an abstract object within the bound model of an ASP.NET MVC view, but I don't know how to bind to that property's properties that are part of its concrete implementation.
public abstract class BasePageVO
{
public string DisplayText { get; set; }
public BaseFoo FooItem { get; set; }
}
public class ConcretePageVO : BasePageVO
{
// some properties
// in a concrete page, the concrete implementation of BaseFoo is known at compile time.
}
public abstract class BaseFoo
{
public string FooText { get; set; }
}
public class ConcreteFoo : BaseFoo
{
public string ConcreteProperty { get; set; }
}
The kicker, and why I have adopted such an unusual class structure, is that the shared partial also needs to know about the FooItem, but only its abstract properties. A much-simplified outline of the structure is below:
DisplayFoo.cshtml:
@model ConcretePageVO
@using (Html.BeginForm("Submit", "Foo", FormMethod.Post)
{
@Html.Partial("DisplayFooShared", @Model)
@Html.EditorFor(x => x.FooItem.ConcreteProperty) @* This fails *@
}
DisplayFooShared.cshtml:
@model BasePageVO
<div>
@Html.DisplayFor(x => x.DisplayText)
@Html.EditorFor(x => x.FooItem.FooText)
@* More properties... *@
</div>
Is there a way to indicate to Razor that the BaseFoo object is of an expected concrete type, and still benefit from how I perform model binding in the shared partial view? I thought I was on the right track with creating my own custom model binding for BaseFoo, like in Darin's answer here, but ASP.NET throws a compilation error that Razor doesn't know what to do with the property name, since it isn't defined.
Is there a way to accomplish binding to these implementation-specific properties and still benefit from the strong typing ASP.NET MVC affords? Was I on the right track with custom binding, but merely botched the implementation? Thanks in advance for any advice.
EDIT: I replaced @Html.EditorFor(x => x.FooItem.ConcreteProperty)
with @Html.EditorFor(x => (x.FooItem as ConcreteFoo).ConcreteProperty)
, which causes the binding to succeed. Is there still a better way to do this, though?