locked
HTTP Put routing attributes (Blazor Server) - controller RRS feed

  • Question

  • User379720387 posted

    With help of MudBlazor and their inline editing table component an selectedItem object of type UserGrid hits my EditUserCommand method in the code section of my .razor page.

    private async void EditUserCommand(UserGrid selectedItem)
        {      
            var httpClient = _clientFactory.CreateClient("ServerAPI");
            await httpClient.PutAsJsonAsync<UserGrid>($"{baseUrl}/api/User/PutUser{selectedItem.UserId}", selectedItem);
            Snackbar.Add($"{selectedItem.uLName} updated!", Severity.Success);
            await Refresh();
        }

    The Put action looks like this:

            [Route("Update/{id}")]
            [HttpPut]
            public async Task<IActionResult> PutUser(UserGrid usergrid)
            {
                context.Entry(usergrid).State = EntityState.Modified;
    
                try
                {
                    await context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw;
                }
    
                return NoContent();
            }

    I am not sure if /PutUser{selectedItem.UserId}", selectedItem); is the correct syntax, that is my first question.

    Second, I have a Route that I call Update but the action method is PutUser.

    Third, PutUser(UserGrid usergrid), I am thinking it should be the Id, but then where do I put the object?

    Please provide clarity on where I need to go with this.

    Sunday, February 21, 2021 5:39 AM

Answers

  • User475983607 posted

    The {id} in the route attribute must match an action argument named variable.   You configured the route as "Update" but the URL does not match.

    wavemaster

    Please provide clarity on where I need to go with this.

    Read the ASP.NET Core attribute reference documentation.   That's what the docs are for.  It seem like you guessed how routes work. https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-5.0

    [Route("Update/{id}")]
    [HttpPut]
    public async Task<IActionResult> PutUser(int id, [FromBody] UserGrid usergrid)
    {
        return Ok(new { id = id, usergrid = usergrid });
    }

    URL

    https://localhost:44352/api/Values/Update/1

    I can't comment on the MudBlazor.  See the MudBlazor docs for assistance with the API.   There can be other issues with your code but we can only see what you share.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, February 21, 2021 12:48 PM
  • User303363814 posted

    Any introduction to the most basic aspects of Entity Framework will explain how to insert data in the database. Nothing to do with Core/Balzor/WebAPI - just entity framework doing the thing it does.

    Have you ever used Entity Framework to insert data before?  Maybe Entity Framework Core Documentation And Tutorials | Learn Entity Framework Core would be useful?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 3:31 AM
  • User475983607 posted

    The URL is missing a forward slash.

    ($"{baseUrl}/api/User/Update/{selectedItem.UserId}"

    You did not share the UserGrid design but the error message indicates UserGrid is not an entity.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 12:31 PM
  • User475983607 posted

    How can I troubleshoot this further, would love to be able to hit the breakpoint inside the PUT action method?

    If this is WASM, you can see the HTTP request in dev tools.

    You are still missing a forward slash to separate the {id] route parameter.

    await httpClient.PutAsJsonAsync<UserGrid>($"{baseUrl}/api/User/Update/{selectedItem.UserId}", selectedItem);

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 11:09 PM

All replies

  • User475983607 posted

    The {id} in the route attribute must match an action argument named variable.   You configured the route as "Update" but the URL does not match.

    wavemaster

    Please provide clarity on where I need to go with this.

    Read the ASP.NET Core attribute reference documentation.   That's what the docs are for.  It seem like you guessed how routes work. https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-5.0

    [Route("Update/{id}")]
    [HttpPut]
    public async Task<IActionResult> PutUser(int id, [FromBody] UserGrid usergrid)
    {
        return Ok(new { id = id, usergrid = usergrid });
    }

    URL

    https://localhost:44352/api/Values/Update/1

    I can't comment on the MudBlazor.  See the MudBlazor docs for assistance with the API.   There can be other issues with your code but we can only see what you share.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, February 21, 2021 12:48 PM
  • User379720387 posted

    Mudblazor hits EditUserCommand() and selectedItem has the edited object :

    private async void EditUserCommand(UserGrid selectedItem)
        {        
            var httpClient = _clientFactory.CreateClient("ServerAPI");
         
            await httpClient.PutAsJsonAsync<UserGrid>($"{baseUrl}/api/User/Update{selectedItem.UserId}", selectedItem);
            
            Snackbar.Add($"{selectedItem.uLName} updated!", Severity.Success);
            
            await Refresh();
        }

    However, the PUT action method I don't think the code gets there.

            [Route("Update/{id}")]
            [HttpPut]
            public async Task<IActionResult> PutUser(int id, [FromBody] UserGrid usergrid)
            {
                Console.WriteLine("inside PutUser");
                
                //return Ok(new { id, usergrid });
    
                context.Entry(usergrid).State = EntityState.Modified;
                Console.WriteLine("passed State Modified");
                try
                {
                    await context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw;
                }
    
                return NoContent();
            }

    I have a breakpoint at { but it never seems to hit. Not seeing the Console.Writeline either in the Output window.

    However, swagger interface works and let's me exercise the PUT action, and it seems to work.

    There has to be something in EditUserCommand, but I am not seeing it.

    Sunday, February 21, 2021 9:10 PM
  • User303363814 posted

    Use the developer tools in your browser (F12 to invoke) and you can see the network request that is made.  It should be quite clear what the problem is (hint: what Url is the request sent to?).

    Sunday, February 21, 2021 11:28 PM
  • User379720387 posted

    Developer tools were useless so far. The source tab keeps stealing focus away from the network tab and nothing ever showed in there.

    Ended up trying it again with Swagger, and it turns out it makes it into the PUT action method, and throws an exception at:

    context.Entry(usergrid).State = EntityState.Modified;
    The entity type 'UserGrid' was not found. Ensure that the entity type has been added to the model.

    Well, that is true, UserGrid is a model that holds data from several tables, using a few Include()'s.

    Do I now need to pull apart the content of usergrid into the individual Entities and save those, or is the EF Core magic that does this for me?

    Monday, February 22, 2021 12:00 AM
  • User303363814 posted

    There is no such thing as 'magic'. (Harry Potter is fiction).   If you want data to change then you need to change it!

    Monday, February 22, 2021 1:44 AM
  • User379720387 posted

    Suppose someone would want to look up how this is done, what would you tell them to search for?

    Not for me, I am just going to search aimlessly through endless google and bing results taking wag after wag only to find examples of Books, TodoItem, User, and Student.

    But wait..... I just found the official Microsoft doc that deals with Core, Blazor and WebAPI....... darn another TodoItem :(

    Monday, February 22, 2021 3:09 AM
  • User303363814 posted

    Any introduction to the most basic aspects of Entity Framework will explain how to insert data in the database. Nothing to do with Core/Balzor/WebAPI - just entity framework doing the thing it does.

    Have you ever used Entity Framework to insert data before?  Maybe Entity Framework Core Documentation And Tutorials | Learn Entity Framework Core would be useful?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 3:31 AM
  • User475983607 posted

    The URL is missing a forward slash.

    ($"{baseUrl}/api/User/Update/{selectedItem.UserId}"

    You did not share the UserGrid design but the error message indicates UserGrid is not an entity.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 12:31 PM
  • User379720387 posted

    @paulthesmith

    ah, yes I know how to do that.

    @mgebhard

    UserGrid is an unfortunate named model of a grouping of entities

    Monday, February 22, 2021 12:38 PM
  • User475983607 posted

    UserGrid is an unfortunate named model of a grouping of entities

    What is a "grouping of entities"?  You are using the type as if the variable is an entity but the error message indicates it is not an entity.

     context.Entry(usergrid).State = EntityState.Modified;

    Monday, February 22, 2021 12:44 PM
  • User379720387 posted

    UserGrid is the model part of MVC.

    I created a model for anything that I want to show on a page, it contains properties of a several Entities.

    At the time I started this I was working on grids (tables), so I ended up with that name.

    The controller returns UserGrid, which it appears I need to pare down to individual chunks before I can do PUT.

    Monday, February 22, 2021 3:46 PM
  • User475983607 posted

    wavemaster

    UserGrid is the model part of MVC.

    I created a model for anything that I want to show on a page, it contains properties of a several Entities.

    Entity Framework is not aware of an MVC model even if that model contains entities and the reason for the error.  Only the entities interact with the database tables.

    Monday, February 22, 2021 3:49 PM
  • User379720387 posted

    Made some progress and I can now do a HTTP PUT from Swagger by cutting and pasting. That completes:

    Server response

    Code Details
    204
    Undocumented
    Response headers
     date: Mon,22 Feb 2021 21:39:12 GMT  server: Microsoft-IIS/10.0  x-powered-by: ASP.NET 

    Responses

    Code Description Links
    200

    Success

    Response 200 and the db was updated.

    Doing this from the Blazor server project is not working still. There are no error messages: not in the browser, and not in the output window.

    I run the API project with the debugger and the Blazor server project with CTRL5.

    It never hits my breakpoint in the edit action method:

    [Route("Update/{id}")]
            [HttpPut]
            public async Task<IActionResult> PutUser(int id, [FromBody] UserGrid user)
            {
                if (id != user.UserId) { return BadRequest(); }
    
                UserProfile editedUser = new();
                editedUser.Email = user.Email;
                editedUser.UserId = (int)id;
                editedUser.ULname = user.uLName;
                editedUser.UFname = user.uFName;
                editedUser.UMobile = user.Mobile;
                editedUser.IsActive = (bool)user.isActive;
                editedUser.TzId = (int)user.tzId;
                editedUser.CountryId = (int)user.countryId;
                editedUser.UInitials = user.uInitials;
                editedUser.IsContact = (bool)user.isContact;
                editedUser.UsuId = (int)user.usuId;
                editedUser.IsClient = (bool)user.isClient;
                editedUser.IsImpActive = (bool)user.isImpActive;
                editedUser.ShowMeridianTime = (bool)user.showMeridianTime;
                
                context.Entry(editedUser).State = EntityState.Modified;
                try
                {
                    await context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw;
                }
    
                return NoContent();
            }

    private async void EditUserCommand(UserGrid selectedItem) { var httpClient = _clientFactory.CreateClient("ServerAPI"); await httpClient.PutAsJsonAsync<UserGrid>($"{baseUrl}/api/User/Update{selectedItem.UserId}", selectedItem); Snackbar.Add($"{selectedItem.uLName} updated!", Severity.Success); await Refresh(); }

    I know EditUserCommand is hit as I see the Snackbar with the correct message, and it stops at my breakpoint.

    selectedItem:

    selectedItem
    {AdvData.ModelEntities.ModelCustom.UserGrid}
        AuthCode: 6948
        Country: "USA"
        Email: "me@outlook.com"
        Mobile: "4105551212"
        UserId: 7
        countryId: 3
        hasRegistered: true
        invUserId: "7"
        isActive: true
        isClient: false
        isContact: false
        isImpActive: false
        showMeridianTime: false
        tzDisplay: "CST"
        tzId: 10
        uFName: "Ellie T"
        uInitials: "LTD"
        uLName: "Deewo"
        usuId: 3
    

    How can I troubleshoot this further, would love to be able to hit the breakpoint inside the PUT action method?

    Typing "response" in the immediate window: "does not exist in the current content"

    Monday, February 22, 2021 10:24 PM
  • User303363814 posted

    Use the developer tools (developer tools tabs do not grab focus - learn to use the tools).  Read the other replies.

    Summary of the way your question sounds "here is some code that I would like to run.  It is not running.  I am not going to show you any reason why it should run.  Please fix."

    Monday, February 22, 2021 10:53 PM
  • User475983607 posted

    How can I troubleshoot this further, would love to be able to hit the breakpoint inside the PUT action method?

    If this is WASM, you can see the HTTP request in dev tools.

    You are still missing a forward slash to separate the {id] route parameter.

    await httpClient.PutAsJsonAsync<UserGrid>($"{baseUrl}/api/User/Update/{selectedItem.UserId}", selectedItem);

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, February 22, 2021 11:09 PM
  • User379720387 posted

    @PaulTheSmith

    browser tools = developer tools

    yes, Sources grabs focus from Network in Edge.......

    I could not explain why it is not hitting my breakpoint.

    Lot of leaves up in the air, rabbit holes all around, sometimes it is difficult to see a clear path.  I never throw some code together and present it here for input. It may look like that as I have no frame of reference outside of what I know a little bit about.

    @mgebhard..... yes, it had seen that slash earlier today, forgot all about it due to all the leaves and rabbit holes. But it did the trick!

    Tuesday, February 23, 2021 1:25 AM