Search code examples
asp.net-mvc-5asp.net-core-mvcattributeroutingasp.net-core-mvc-2.0asp.net-core-mvc-2.1

Model Binding not working with Attribute Routing in .net Core 2.1


I can get model binding to work fine without attribute routing - eg:

/// <summary>
/// Collect user details
/// </summary>
public IActionResult RegisterDetails(Guid CustomerId)
{
    var Details = new Details()
    {
        CustomerID = CustomerId
    };

    return View(Details);
}

/// <summary>
/// Save user details in Db if valid
/// </summary>
[HttpPost]
public IActionResult RegisterDetails(Details Details)
{
    if (ModelState.IsValid)
    {
        // Do stuff
    }

    // Error, return ViewModel to view
    return View(RegisterDetails);
}

But I'm not sure how to pass the model to the method that handles it. When I submit the form it runs the original method, not the one under [HttpPost] - it keeps posting to the original method again and again (where // Do stuff is - when I do this:

/// <summary>
/// Collect user details
/// </summary>
[Route("Register/Details/{CustomerId}")]
public IActionResult RegisterDetails(Guid CustomerId)
{
    var Details = new Details()
    {
        CustomerID = CustomerId
    };

    return View(Details);
}

/// <summary>
/// Save user details in Db if valid
/// </summary>
[HttpPost]
[Route("Register/Details")]
public IActionResult RegisterDetails(Details Details)
{
    if (ModelState.IsValid)
    {
        // Do stuff
    }

    // Error, return ViewModel to view
    return View(RegisterDetails);
}

How can I bind the model correctly when using attribute routing?

I searched Google - I found things that didn't help, eg this: https://www.red-gate.com/simple-talk/dotnet/asp-net/improved-model-binding-asp-net-core/

thx

Update

I've also noticed the CustomerId is being appended to the Url, even after the form has been posted. I don't think this happened in MVC 5 and don't require this, the CustomerId is hidden in the page.

How can I remove this (it's causing the route to not match the [HttpPost] decorated method.


Solution

  • Normally, you can add the attribute "route" through the API Class controller as a base path and then adding parameters. I also tried to add always the verb for the controller for a better understanding...

    [Route("Register/Details/")]
    public class RegistrerExampleController : ControllerBase
    {
    
        /// <summary>
        /// Collect user details
        /// </summary>
        [HttpGet("{CustomerId}", Name = nameof(RegisterDetails))]
        public IActionResult RegisterDetails(Guid CustomerId)
        {
            var Details = new Details()
            {
                CustomerID = CustomerId
            };
    
            return View(Details);
        }
    
        /// <summary>
        /// Save user details in Db if valid
        /// </summary>
        [HttpPost]
        public IActionResult RegisterDetails(Details Details)
        {
            if (ModelState.IsValid)
            {
                // Do stuff
            }
    
            // Error, return ViewModel to view
            return View(RegisterDetails);
        }
    }
    

    Have you tried this?