0

I've been trying to learn Blazor WebAssembly programming and have been doing a follow-along project along with the Pluralsight course I'm working on.

What happens is that the PutAsync() method in the following code fails:

        public async Task UpdateEmployee(Employee employee)
        {
            try
            {
                var jsonString = JsonSerializer.Serialize(employee).ToString();
                var employeeJson =
                    new StringContent(JsonSerializer.Serialize(employee), Encoding.UTF8, "application/json");
                await _httpClient.PutAsync($"/api/employee", employeeJson);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }

        }

This code is located in a service class, and the target method that has the HttpPut attribute either doesn't seem to get called, or the breakpoint I place in it never gets hit.

  [HttpPut]
        public IActionResult UpdateEmployee([FromBody] Employee employee)
        {
            if (employee == null)
                return BadRequest();

            if (employee.FirstName == string.Empty || employee.LastName == string.Empty)
            {
                ModelState.AddModelError("Name/FirstName", "The name or first name shouldn't be empty");
            }

            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            var employeeToUpdate = _employeeRepository.GetEmployeeById(employee.EmployeeId);

            if (employeeToUpdate == null)
                return NotFound();

            _employeeRepository.UpdateEmployee(employee);

            return NoContent(); //success
        }

I put the breakpoint on the if (employee == null) line, but it doesn't get hit. I initially had a lot of problems with breakpoints not being hit, but ever since I switched from Firefox to Chrome for my testing, it's been a lot better. Yet, the execution doesn't seem to get here. The routing attributes at the top of this target class looks like the following:

 [Route("api/[controller]")]
 [ApiController]

The class itself is called EmployeeController, so I would think that the "api/employee" attribute should reach it.

I've added a try/catch block around the failing code in the first code block I've posted, and when I step through, I see that there's an exception that gets thrown after I try to step over the PutAsync() method. But when I go to command window to se what the content of ex.Message is, I get the "Unable to Evaluate" error in Visual Studio.

enter image description here

If I step through, I see the execution hitting some bound fields in the Razor file that displays the edit form, but I don't know enough about Razor to really deduce what is going on. There are numerous fields in there that look like this:

   <div class="form-group row">
            <label for="lastName" class="col-sm-3">Last name: </label>
            <InputText id="lastName" @bind-Value="@Employee.LastName" class="form-control col-sm-8" placeholder="Enter last name"></InputText>
        </div>

        <div class="form-group row">
            <label for="firstName" class="col-sm-3">First name: </label>
            <InputText id="firstName" class="form-control col-sm-8" @bind-Value="@Employee.FirstName" placeholder="Enter first name"></InputText>
        </div>

        <div class="form-group row">
            <label for="birthdate" class="col-sm-3">Birthdate: </label>
            <InputDate id="birthdate" class="form-control col-sm-8" @bind-Value="@Employee.BirthDate" placeholder="Enter birthdate"></InputDate>
        </div>

        <div class="form-group row">
            <label for="email" class="col-sm-3">Email: </label>
            <InputText id="email" class="form-control col-sm-8" @bind-Value="@Employee.Email" placeholder="Enter email"></InputText>
        </div>

And then, at some point, while stepping through, a lot of the fields get skipped, and the execution seems to leave the Razor file abruptly. I am not sure what to make of this, and since I have been largely absent from .Net for the last several years, it all does feel a bit overwhelming. I am not quite sure how the PutAsync() method call failure really translates into these possible data binding errors, but I am guessing that PutAsync() is just a vehicle to call whatever code has the [HttpPut] attribute, and that any kind of exception anywhere down the line from this method call will cause the PutAsync() call to fail. Would that be accurate or not?

Ivan
  • 103
  • 2
  • 8
  • 1
    You need to know that error, replace System.Diagnostics.Debug. with Console. (output shows up in the Browser Dev Tools comsole). – H H Jun 21 '22 at 01:26
  • 1
    the endpoint you are trying to hit, whats the response when you try to access it from brower manually? – Wajeeh Hasan Jun 21 '22 at 03:33
  • 1
    also can you add `[Route("[action]")]` underneath `[HttpPut]` and see if it works – Wajeeh Hasan Jun 21 '22 at 03:40
  • Thank you for the Browser Dev Tools tip. I didn't know about that one and kept wondering where the console output would have been going. Well, I changed the code and got this: Access to fetch at 'https://localhost:44340/api/employee' from origin 'https://localhost:44362' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response. I added the AllowAnyMethods() call to the CORS policy in the startup.cs of the web service, and everything works. I know this isn't a sound programming practice, but I can at least keep going with the course. – Ivan Jun 21 '22 at 23:06

3 Answers3

1

try to await "api/employee"

var employeeToUpdate = await _employeeRepository.GetEmployeeById(employee.EmployeeId);
spacemonki
  • 291
  • 2
  • 13
1
  1. Don't use Built-in form components without EditForm and model or EditContext.
  2. Use DataAnnotationsValidator and/or ValidationSummary component to validate your form before submitting.
  3. use OnValidSubmit method to submit your form only when has a validate controls.
  4. If you don't want to use OnValidSubmit, check if your EditContext validate before request PutAsync().
  5. Please check Microsoft doc for more information, I am sure that is more clear than your course that you are following.
Nb777
  • 1,658
  • 8
  • 27
1

Thank you all so much for all the helpful advice, especially the Browser Dev Tools console tip.

So, I changed the System.Diagnostics.Debug.WriteLine(ex.Message) line to Console(ex.Message), and the error I saw in the Browser Dev Tools console was:

Access to fetch at 'https://localhost:44340/api/employee' from origin 'https://localhost:44362' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

I went to the ConfigureServices() method in the startup.cs file of the web service, and I changed the code from

    services.AddCors(options =>
            {
                options.AddPolicy("Open", builder => builder.AllowAnyOrigin().AllowAnyHeader());
            });

to

            services.AddCors(options =>
            {
                options.AddPolicy("Open", builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
            });

The error is gone, and the employee record gets saved correctly now. I do realize that this isn't exactly a sound programming practice to call something like AllowAnyMethod(), but for the purposes of this course, it's sufficient for now. Thank you all again!

Ivan
  • 103
  • 2
  • 8