3

When I am making a WebAPI call I want to find out how to pass back ModelState errors to my Blazor application.

The DataAnnotations all validate correctly but, if I do any other types of validation (once past the ModelState.IsValid call), I can't get those errors that I add to the ModelState to pass back to Blazor. What am I missing?

Blazor page

...
   <EditForm Model="@_user" OnValidSubmit="@Update">
      <DataAnnotationsValidator />
      <ValidationSummary />
      <div class="container">
         <div class="row">
            <div class="col-md-3">Name:</div>
            <div class="col-md-9"><InputText id="Name" @bind-Value="@_user.UserName" class="form-control" /></div>
         </div>
         @if (_user.isNew)
         {
         <div class="row">
            <div class="col-md-3">Password:</div>
            <div class="col-md-9"><InputText id="Name" @bind-Value="@_user.Password" class="form-control" type="password" /></div>
         </div>
         <div class="row">
            <div class="col-md-3">Validate your password:</div>
            <div class="col-md-9"><InputText id="Name" @bind-Value="@_user.ValidatePassword" class="form-control" type="password" /></div>
         </div>
         }
         <div class="row">
            <div class="col-md-3">Email:</div>
            <div class="col-md-9"><InputText id="Name" @bind-Value="@_user.Email" class="form-control" /></div>
         </div>
         <div class="row">
            <div class="col-md-3">Roles:</div>
            <div class="col-md-9">
               @foreach (IdentityRole role in _roles)
               {
                  bool isChecked = _user.UserRoles.Any(r => r.Id == role.Id);
                  <input type="checkbox" Id="@role.Id" name="@role.Id"
                         Class="form-control" checked="@isChecked" @onchange="@(e => RoleChecked(e, role.Id))" />
                  @role.Name
               }
            </div>
         </div>
         <button type="submit" class="btn btn-@buttonClass">@buttonText</button>
      </div>
   </EditForm>
}

@functions {
   [Parameter]
   string id { get; set; } = "";
   private UserViewModel _user { get; set; }
...
   private async Task Update()
   {
      if (id != "")
      {
         await apiClient.UpdateUserAsync(_user);
      }
      else
      {
         await apiClient.AddUserAsync(_user);
      }
      UriHelper.NavigateTo("admin/users");
   }
...

WebAPI Controller

[HttpPost]
      public async Task<IActionResult> Post([FromBody] UserViewModel applicationUser)
      {
         if (applicationUser == null)
         {
            _logger.LogError($"ApplicationUser object null");
            return BadRequest("ApplicationUser object is null");
         }
         if (!ModelState.IsValid)
         {
            _logger.LogWarn("ApplicationUser object invalid");
            return BadRequest(ModelState);
         }
         else
         {
            _logger.LogDebug($"Creating ApplicationUser {applicationUser.UserName}");
            var obj = new ApplicationUser();
            obj.Map(applicationUser);
            IdentityResult result = await _userManager.CreateAsync(obj, applicationUser.Password);
            if (result.Succeeded)
            {
               //put the newly created user back on top of the parameter for role creation
               applicationUser.Map(obj);
               await IdentityHelpers.UpdateUserRoles(_userManager, applicationUser);
               return CreatedAtRoute("", new { id = applicationUser.Id }, applicationUser);
            }
            else
            {
               _logger.LogWarn("ApplicationUser object could not be created");
               result.Errors.ToList().ForEach(e => ModelState.AddModelError(e.Code, e.Description));
               return BadRequest(ModelState);
            }
         }
      }

How do I pass back ModelState errors to Blazor so that it will respond to those in the same way that it would DataAnnotations (or model validation)?

Rabbitslayer
  • 127
  • 2
  • 7
  • Yep I'm having the same issue hope someone has an idea? – Wizzard Nov 18 '19 at 23:44
  • I was able to get around this by utilizing the IValidatableObject on my classes that I wanted to custom validate. Those ValidationResults work within Blazor just like DataAnnotations – Rabbitslayer Nov 19 '19 at 16:34
  • That sounds great will look into it myself :) – Wizzard Nov 21 '19 at 13:03
  • @Rabbitslayer, could you share the code regarding the IValidatableObject ? – Martin Overgaard Dec 05 '20 at 10:10
  • Sure. Here is the header for the class I want to IValidateObject `public class ApplicationUserViewModel : ApplicationUser, IValidatableObject` Then extend the Validate method in that class and it should bubble up to the UI `public IEnumerable Validate(ValidationContext validationContext)` – Rabbitslayer Jan 04 '21 at 19:03

0 Answers0