How to create HTTP Error Handling for the PUT method?

sblb 1,231 Reputation points
2023-09-20T15:57:55.88+00:00

Hi, I would like to know how create HTTP Error Handling for the PUT method and rendering the information to user in UI. I guess that it's also possible to make GLobal HTTP Error Handling for all methods!

I've created the put method which, when two users modify the data and validate it in the user interface, I want to display the message e.g. from SetDbErrorMessage

I've added in class model Timestamp attribute.

It's really the first time I've done this, and I'll need some help;

Thanks in advance to your help!


        [HttpPut]
        public async Task<IActionResult> Put(ProjetModel projetModel)
        {
            _context.Entry(projetModel).State = EntityState.Modified;

            try
             {
               await _context.SaveChangesAsync();
             }
             catch (DbUpdateConcurrencyException ex)
              {
                var exceptionEntry = ex.Entries.Single();
               var clientValues = (ProjetModel)exceptionEntry.Entity;
               var databaseEntry = exceptionEntry.GetDatabaseValues();
               var dbValues = (ProjetModel)databaseEntry.ToObject();
               await SetDbErrorMessage(dbValues, clientValues);

              projetModel.ConcurrencyToken = (byte[])dbValues.ConcurrencyToken;
              ModelState.Remove($"{nameof(projetModel)}.{nameof(projetModel.ConcurrencyToken)}");
                 return BadRequest(ModelState);
            }
            return NoContent();
        }


 private async Task SetDbErrorMessage(ProjetModel dbValues,
                                         ProjetModel clientValues)
            {

                    if (dbValues.Title != clientValues.Title)
                    {
                        ModelState.AddModelError("ProjetModel.Title",
                            $"Current value: {dbValues.Title}");
                    }
                    if (dbValues.Type != clientValues.Type)
                    {
                        ModelState.AddModelError("ProjetModel.Type",
                            $"Current value: {dbValues.Type:c}");
                    }
                    if (dbValues.DateProjet != clientValues.DateProjet)
                    {
                        ModelState.AddModelError("ProjetModel.DateProjet",
                            $"Current value: {dbValues.DateProjet:d}");
                    }
                    if (dbValues.Statut != clientValues.Statut)
                    {
                        ModelState.AddModelError("ProjetModel.Statut",
                            $"Current value: {dbValues.Statut:d}");
                    }
            ModelState.AddModelError(string.Empty,
                                       "The record you attempted to edit "
                                     + "was modified by another user after you. The "
                                     + "edit operation was canceled and the current values in the database "
                                     + "have been displayed. If you still want to edit this record, click "
                                     + "the Save button again.");
        }        

I invoke the post method as below

ProjetModel? projetBEToUpdate;
 async Task OnUpdateRow(ProjetModel newRow)
        {
            using var response = 
            await client.PutAsJsonAsync("api/projetbe", newRow);
         if(!response.IsSuccessStatusCode) 
          {         
               await client.PutAsJsonAsync("api/projetbe", newRow);
              return;
          } 
            dev = await response.Content.ReadFromJsonAsync<ProjetModel>();
            uriHelper.NavigateTo("ppage");
            projetBEToUpdate = null;

        }  

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,577 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Ping Ni-MSFT 4,335 Reputation points Microsoft Vendor
    2023-09-21T07:30:20.1233333+00:00

    Hi @sblb ,

    A simple demo you could follow:

    1.Custom validation component

    public class CustomValidation : ComponentBase
    {
        private ValidationMessageStore? messageStore;
    
        [CascadingParameter]
        private EditContext? CurrentEditContext { get; set; }
    
        protected override void OnInitialized()
        {
            if (CurrentEditContext is null)
            {
                throw new InvalidOperationException(
                    $"{nameof(CustomValidation)} requires a cascading " +
                    $"parameter of type {nameof(EditContext)}. " +
                    $"For example, you can use {nameof(CustomValidation)} " +
                    $"inside an {nameof(EditForm)}.");
            }
    
            messageStore = new(CurrentEditContext);
    
            CurrentEditContext.OnValidationRequested += (s, e) =>
                messageStore?.Clear();
            CurrentEditContext.OnFieldChanged += (s, e) =>
                messageStore?.Clear(e.FieldIdentifier);
        }
    
        public void DisplayErrors(Dictionary<string, List<string>> errors)
        {
            if (CurrentEditContext is not null)
            {
                foreach (var err in errors)
                {
                    messageStore?.Add(CurrentEditContext.Field(err.Key), err.Value);
                }
    
                CurrentEditContext.NotifyValidationStateChanged();
            }
        }
    
        public void ClearErrors()
        {
            messageStore?.Clear();
            CurrentEditContext?.NotifyValidationStateChanged();
        }
    }
    

    2.modify your razor

    ProjetModel? projetBEToUpdate = new();
    private CustomValidation? customValidation;
    async Task OnUpdateRow(ProjetModel newRow)
    {
        using var response =
        await client.PutAsJsonAsync("api/projetbe",newRow);
    
    
        var errors = await response.Content
            .ReadFromJsonAsync<Dictionary<string, List<string>>>() ??
            new Dictionary<string, List<string>>(); if (!response.IsSuccessStatusCode)
        {
            customValidation?.DisplayErrors(errors);
            //await client.PutAsJsonAsync("api/projetbe", newRow);
            return;
        }
        //...
    
    }
    

    More details you could refer to this official document here.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Rena


  2. sblb 1,231 Reputation points
    2023-09-23T07:44:04.8433333+00:00

    @Ping Ni-MSFT my previous message wasn't clear.

    I don't use <EditForm> in this case, so I can't use your approach, it seems to me.

    In my case, when two users enter a value at the same time, I send a message to the user telling him to validate a second time for the value to be taken into account.

    In the razor page there's a DataGrid with an online edit mode; I've put screenshot of what I want to do

    User's image

    I think that the put method is good. I've to added the message when I invoke the put method in razor page (see first post) ; It' here where I don't really know how I can do that!

    I use Timestamp attribut in class model; The question I asked me How I can acces to the data from concurrency to rendering the value register from database.

    User's image

    I've put the breakpoint in put method

    User's image

    Thanks in advance to your help!


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.