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.
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.