ASP.Net Core MVC 中的模型绑定/ViewModel 绑定

Model binding / ViewModel binding in ASP.Net Core MVC

让我们从简单的代码开始:

public class SomeViewModel 
{
    public int State { get; set; }
}

public class SomeController : Controller
{
    public IActionResult DoSomething(int state)
    {
        var viewModel = new SomeViewModel();
        
        if(state % 2 == 0)
            viewModel.State = state * 2;
        else
            viewModel.State = state;
        
        return View("MyView", viewModel)
    }
}

MyView.cshtml:

@model SomeViewModel;

...
    <form method="get" asp-action="BlablaAction" asp-controller="OtherController">
        <input asp-for="State">
        <button type="submit">Save</button>
    </form>

...

我提出要求:

/some/dosomething?state=4 => 输入值 = 4

/some/dosomething?state=5 => 输入值 = 5

/some/dosomething?state=6 => 输入值 = 6

/some/dosomething?state=7 => 输入值 = 7

但根据我在 DoSomething 操作中的逻辑,它应该是:

/some/dosomething?state=4 => 输入值 = 8

/some/dosomething?state=5 => 输入值 = 5

/some/dosomething?state=6 => 输入值 = 12

/some/dosomething?state=7 => 输入值 = 7

我的问题是:为什么将输入值分配给查询参数而不是传递的模型对象的 属性... 第二件事我知道我可以将 param 的名称从 state 更改为 param1 但也许还有其他方法可以做到...... 我读过 2 本关于 ASP.net 核心的书,但没有遇到过任何相关内容。

如果您的表单方法是“获取”输入作为查询字符串发送,但如果您想 post 它们作为表单,您应该 post 您的表单并分配类型“post”到您的表单方法。

  <form method="post" asp-action="DoSomething" asp-controller="Some">
        <input asp-for="State">
        <button type="submit">Save</button>
    </form>

在此代码中,如果您的操作参数是 SomeViewModel 类型,则 State 将绑定到您的 SomeViewModel。

默认情况下,如果我们将 GET 分配给表单的方法属性,它会通过查询字符串公开数据。为了避免这种情况,我们将方法属性设置为 POST

<form method="post" asp-action="DoSomething" asp-controller="Some">
        <input asp-for="State">
        <button type="submit">Save</button>
    </form>

其次,.NET Core提高了安全性,所以官方文档推荐使用Model in Post这样的方法。 (这是可选的最佳实践。不是强制性的)

public class StateModel 
{
    public int State { get; set; }
}

public class SomeController : Controller
{
    public IActionResult DoSomething(StateModel model)
    {
        var viewModel = new SomeViewModel();
        
        if(model.State % 2 == 0)
            viewModel.State = state * 2;
        else
            viewModel.State = state;
        
        return View("MyView", viewModel)
    }
}

<input asp-for="">标签符合HTML时,它在从您的视图模型获取值之前从 ModelState 获取值,因此您可以清除 ModelState

中的值
public IActionResult DoSomething(int state)

        {
            var viewModel = new SomeViewModel();

            if (state % 2 == 0)
            {
                viewModel.State = state * 2;
                ModelState.Clear();
            }
            else
                viewModel.State = state;
           
            return View(viewModel);
        }

另外,你可以把代码放在controller里面,只修改label:

<input type="number" data-val="true" data-val-required="The State field is required." id="State" name="State" value="@Model.State">