1

我可以让模型绑定在没有属性路由的情况下正常工作 - 例如:

/// <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);
}

但我不确定如何将模型传递给处理它的方法。当我提交表单时,它运行原始方法,而不是 [HttpPost] 下的方法 - 它一次又一次地发布到原始方法( // Do stuff 是 - 当我这样做时:

/// <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);
}

使用属性路由时如何正确绑定模型?

我搜索了谷歌 - 我发现了一些没有帮助的东西,例如: https ://www.red-gate.com/simple-talk/dotnet/asp-net/improved-model-binding-asp-net-core/

谢谢

更新

我还注意到 CustomerId 被附加到 Url,即使在表单发布之后也是如此。我不认为这发生在 MVC 5 中并且不需要这个,CustomerId 隐藏在页面中。

我该如何删除它(它导致路由与 [HttpPost] 装饰方法不匹配。

4

3 回答 3

2

通常,您可以通过 API 类控制器添加属性“路由”作为基本路径,然后添加参数。我还尝试始终为控制器添加动词,以便更好地理解......

[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);
    }
}

你试过这个吗?

于 2018-10-03T15:31:33.643 回答
1

The issue is two-fold. First, you have your RegisterDetails(Guid CustomerId) action with the route set via the Route attribute. This opens it up to accept all the HTTP verbs: GET, POST, etc. Second, although you did not post your view, I can assume that you likely have a form with an empty action, i.e.:

 <form method="post">
     ...
 </form>

That's going to default to posting back to the same page, which here in this scenario would /Register/Details/{CustomerId}. Since that route does not match your action explicitly marked as HttpPost and the action it does match accepts a POST (because of using Route), the action that takes a customer id is called again. Since there's no code to actually handle a post in that, it simply reloads your page.

First and foremost, you should use the explicit HTTP verb attributes rather than Route on your actions, i.e.:

[HttpGet("Register/Details/{CustomerId}")]
public IActionResult RegisterDetails(Guid CustomerId)

[HttpPost("Register/Details")]
public IActionResult RegisterDetails(Details Details)

Then, if you want to keep this route scheme, you need to be explicit with your form. However, since both actions have the same name, that's a bit difficult to do. ASP.NET Core is going to attempt to backfill the CustomerId portion of the route because it already exists in the route data. You have three options:

  1. Use different action names. Then, you can explicitly bind your form to your post action:

    [HttpPost("Register/Details")]
    public IActionResult RegisterDetailsPost(Details Details)
    

    Then:

    <form asp-action="RegisterDetailsPost" method="post">
    
  2. Employ route names:

    [HttpPost("Register/Details", Name = "RegisterDetailsPost")]
    public IActionResult RegisterDetails(Details Details)
    

    Then:

    <form asp-route="RegisterDetailsPost" method="post">
    
  3. Don't make the customer id part of the initial route. If the two routes actually match, then the right one will be pull based on the HTTP verb in play. In other words:

    [HttpGet("Register/Details")]
    public IActionResult RegisterDetails(Guid CustomerId)
    

    You can still supply a customer id, but you need to use the query string, i.e. /Register/Details?CustomerId=123456. Generating the URL in your links and such will be no different. ASP.NET Core will attach any route data included that's no explicitly a route param as a query string param automatically. In other words, you can still just do something like:

    <a asp-action="RegisterDetails" asp-route-customerId="123456">Click me</a>
    
于 2018-10-03T15:56:22.173 回答
0

尝试使用 FromBody 属性。

public IActionResult RegisterDetails([FromBody]Details Details)
于 2018-11-14T07:46:20.557 回答