subclass tag helper

subclass tag helper makes further fields are rendered and properly processed by the model binder when a property contains a subclass of its type.

If the properties added by each subclass are enclosed within different subclass tag helpers one for each subclass of the property type, then the extra properties of each subclass appear only if the run-timeofbject is of that type. That is they appear only when needed. Moreover, in case they appear in edit mode and the View is submitted, then the correct subclass will be recognized by the model binder with all extra-properties properly filled.

Example

<h3>Generic Person</h3>
<div class="form-group">
    <label asp-for="Test.Name" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Test.Name" class="form-control" />
        <span asp-validation-for="Test.Name" class="text-danger"></span>
    </div>
</div>
<div class="form-group">
    <label asp-for="Test.Surname" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Test.Surname" class="form-control" />
        <span asp-validation-for="Test.Surname" class="text-danger"></span>
    </div>
</div>
 
<subclass asp-for="Test" subclass-type="@typeof(Customer)">
    @{
        {
            var customer = Model.Test as Customer;
            <div class="form-group">
                <label asp-for="@customer.RegisterNumber" class="col-md-2 control-label"></label>
                <div class="col-md-10">
                    <input asp-for="@customer.RegisterNumber" class="form-control" />
                    <span asp-validation-for="@customer.RegisterNumber" class="text-danger"></span>
                </div>
            </div>
 
 
        }
    }
</subclass>
<subclass asp-for="Test" subclass-type="@typeof(Employee)">
    @{
        {
            var employee = Model.Test as Employee;
            <div class="form-group">
                <label asp-for="@employee.Matr" class="col-md-2 control-label"></label>
                <div class="col-md-10">
                    <input asp-for="@employee.Matr" class="form-control" />
                    <span asp-validation-for="@employee.Matr" class="text-danger"></span>
                </div>
            </div>
 
 
        }
    }
</subclass>

Important: The variable where to store the casted object must start with a lower case letter, otherwise the subclass assumes that its name must be included in all input names, thus causing model binding to fail.

Please notice: double "{{" creates a local scope. This way the customer and employee variables are not defined outside of this scope. The usage of "{{" is not obligatory for the correct operation of the subclass tag helper. However, it is good practice to limit variables scope to the chunk of code where they are used.

Important: If the model passed to the subclass tag helper is null all fields are visible, since in that case an "item creation" mode is assumed. Thus, when the model is null the developer should use JavaScript to remove/add from/to the DOM the unwanted sub-class fields, as user selects somehow which sub type it would like to create.

See it live

Preventing denial of service attacks: RunTimeTypeAttribute

Since the type to generate when the page is submitted must be somehow stored in the page itself, a malicious user might modify this info to instantiate a "dangerous type". The [RunTimeType] attribute prevents similar attack, since only classes decorated with this attribute or their ancestors are processed by the subclass engine.

Important: subclasses are properly processed also by Json serializer/deserializer when they (or some of their descendants) are decorated with the [RunTimeType] attribute.

Tag helper properties

Tag name
subclass
asp-for: expression
the property containing the class to process
subclass-type: Type
The subclass of the property type whose properties will be rendered within the tag helper instance.

Fork me on GitHub