I have a page which is comprised of other pages which are both partials and editor templates. I have the templates showing properly in both cases with the exception of validation messages. When I render the razor page template shown below as a partial using @Html.Partial(...) I get the expected validation messages next to each of the fields (but form data is not included from fields within the template rendered as a Partial) when I use the @Html.EditorFor(...) helper the page is rendered as expected and the field values are included as part of the form data but for some reason the validation messages aren't showing. It is the exact same template just using a different html helper.
Razor page template:
@ModelType PreferencesModel
@If Model.Preferences.Count > 0 Then
@For Each kvp As KeyValuePair(Of String, Pref) In Model.Preferences
@<div class="row">
<div class="col-md-2">
@Html.Label(Model.Preferences(kvp.Key).Name)
</div>
<div class="col-md-2">
@If kvp.Value.IsReadOnly Then
@kvp.Value.CurrentValue
Else
@Html.TextBoxFor(Function(m) m.Preferences(kvp.Key).CurrentValue)
End If
</div>
<div class="col-md-2">
@Html.ValidationMessage(kvp.Key)
</div>
</div>
Next
End If
Razor parent page:
@ModelType EditPreferencesModel
@Using Html.BeginForm("EditPrefs", "PrefsController", FormMethod.Post, New With {.id = "updatePrefs", .class = "form-horizontal", .role = "form"})
@Html.AntiForgeryToken
@If Not Model.PreferencesModel Is Nothing Then
@Html.EditorFor(Function(m) m.PreferencesModel)
@*@Html.Partial("~/Views/Prefs/EditorTemplates/Pref.vbhtml", Model.PreferencesModel)*@
End If
End Using
Models:
public class Pref
{
public string Name { get; set; }
public string CurrentValue { get; set; }
}
public class PreferencesModel
{
public Dictionary<string, Pref> Preferences { get; set; }
}
public class EditPreferencesModel
{
public PreferencesModel PreferencesModel { get; set; }
}
PrefsController Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditPrefs(EditPreferencesModel model, string id)
{
try
{
bool preferenceChangesAreValid = false;
try {
ValidatePreferenceChanges(model.PreferencesModel);
preferenceChangesAreValid = true;
}
catch(Exception e)
{
Logger.Error("Invalid preference information entered. Error: " + e.ToString());
}
if (preferenceChangesAreValid)
{
UpdatePreferencesFromViewModel(model.PreferencesModel);
... redirect to another view ...
}
model = PrepareEditPreferencesViewModel(model);
}
catch (Exception e)
{
Logger.Error("An unexpected error occurred. Error: " + e.ToString());
ModelState.AddModelError("", "An error occurred with your request, please try again later.");
}
return View(model);
}
private void ValidatePreferenceChanges(PreferencesModel model)
{
... iterate preferences and validate ...
if (preferenceIsInvalid)
ModelState.AddModelError(kvp.Key, "Numeric value expected.");
...
}
As I mentioned above, when rendering this as a partial, the Model errors are displayed as expected but when I render this as an EditorFor template the errors aren't displayed.
I've set a breakpoint on the template when using EditorFor and upon inspection of the ViewState I can see that the errors I expect to see on the validation message fields are indeed present in the ModelState.
Am I misusing EditorFor?
Is there an extra step needed to get the template when using EditorFor to recognize the errors for each of the fields?
Is this expected behavior for EditorFor?
EditPreferencesModel
class has no propertyPreferencesModel
, so when your view's model isEditPreferencesModel
and you referenceModel.PreferencesModel
you should be getting a runtime error. – Chris Pratt