Search code examples
asp.netasp.net-coreasp.net-core-2.2asp.net-core-tag-helpers

ASP CORE: @Html.ValidationMessage migration to asp-validation-for or similar tag helper


How to setup the asp-validation-for with string value, not with expression?

I want to migrate the multiselect list:

@Html.ListBox("Privileges", ViewBag.PrivilegesMultiSelectList as MultiSelectList)
@Html.ValidationMessage("Privileges", "")

to

<select multiple="multiple" name="Privileges" asp-items="@ViewBag.PrivilegesMultiSelectList"></select>
<span asp-validation-for="Privileges" class="text-danger"></span>

But the last line is invalid:

Error CS1061 '...Model' does not contain a definition for 'Privileges' and no accessible extension method 'Privileges' accepting a first argument of type '..Model' could be found (are you missing a using directive or an assembly reference?)

I want to stay using tag-helper because of consistency.


Solution

  • This asp-validation-for="Privileges" is trying to look for Privileges property in your model (not ViewBag). If it doesn't exist, it will give you that error. That line is the equivalent of ValidationMessageFor(), and afaik there's no equivalent in .net core for ValidationMessage().

    Have a look at the asp-validation-for tag helper, which as stated should align with the name of another taghelper.

    How to setup the asp-validation-for with string value, not with expression?

    Again, there's no equivalent for ValidationMessage() it in TagHelpers. So you can just use @Html.ValidationMessage().

    https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.2

    it's important to recognize that Tag Helpers don't replace HTML Helpers and there's not a Tag Helper for each HTML Helper.

    You could also just write your own tag helper with the ValidationMessage HtmlHelper

    Some advice from the docs regarding ViewBags:

    We don't recommend using ViewBag or ViewData with the Select Tag Helper. A view model is more robust at providing MVC metadata and generally less problematic.

    A better approach:

    You will need to add the selected Privilege(s) to your model that you wish to return.

    public class CustomViewModel {
        [Required]
        public string Privilege { get; set; } // update if you want to return multiple privileges
    
        public List<SelectListItem> PrivilegesMultiSelectList { get; set; }
    }
    

    and then use that in your View @model CustomViewModel.

    Using asp-for="Privilege" on your select, it becomes m => m.Privilege.

    https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.2

    The asp-for attribute value is a special case and doesn't require a Model prefix, the other Tag Helper attributes do (such as asp-items)

    You can then just write it as such:

    <select asp-for="Privilege" asp-items="@Model.PrivilegesMultiSelectList"></select> 
    <span asp-validation-for="Privilege" class="text-danger"></span>
    

    I hope this helps.