ModelState.isValid为假,因为Id 模型属性与传递的参数冲突

本文关键字:冲突 参数 属性 模型 为假 isValid 因为 Id ModelState | 更新日期: 2023-09-27 17:55:22

我对MVC仍然很陌生,很难弄清楚如何最好地解决这个问题。

我有一个自动脚手架"Create" (GET)操作的修改版本,该操作采用可选参数(下拉列表的默认值)。 然后,它将表单提交到"Create" (HTTPPost)操作。

public ActionResult Create(string id = null)
{ 
    //use id to pick a default item in a drop down list.
}
[HttpPost]
public ActionResult Create(Registration registration)
{ 
    //this method doesn't care one iota what was passed to the GET method
    // but registration.id is invalid because it's trying to set it to the value that was passed to the get method.  If id in the get method is not passed, then everything is fine
}

问题是,如果将值传递给 GET 创建操作,则POST create操作上的ModelState.isValid为 false,因为它试图将传递给 GET 操作的值填充到 POST 操作中模型的主键 (Id) 字段中(应省略,因为它是自动生成的。

我知道我可以将主键列名称更改为 Id 以外的名称,但我无法控制数据库,并且正在尝试找出解决此问题的另一种补救措施。

如果我尝试将 GET 操作上的参数从"id"重命名为其他名称,那么我必须将链接从 CREATE/paramValue 更改为CREATE/?paramName=paramValue,我宁愿不这样做。 (尽管如果这是唯一简单的方法,我会的)。

有没有办法使 POST 操作忽略传递给 GET 操作的值?

ModelState.isValid为假,因为Id 模型属性与传递的参数冲突

我认为您要做的是使用控制器应该创建的对象类型的 ID 参数化控制器的 Create 方法。

虽然 MVC 中没有关于参数名称 ASP.NET 硬性约定,但我认为大多数人都希望名为 id 的参数引用正在处理的对象,而不是它的属性。

考虑到这一点,我对你的建议是执行以下操作:

  1. Create 方法的 GET 版本中的参数重命名为合适的名称,例如 typeId 或其他名称,因此签名看起来像public ActionResult Create(string typeId = null)

  2. MvcApplication中添加自定义路由,这将使您拥有格式良好的/Create/typeId,而不是强制具有/Create?typeId=value

为此,

可以在默认路由之前添加以下代码行:

routes.MapRoute
(
    name: "CreateGet",
    url: "Controller/Create/{typeId}",
    defaults: new
    {
        controller = "Controller",
        action = "Create",
        typeId = UrlParameter.Optional
    }
);

默认路由如下所示:

routes.MapRoute
(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new
    {
        controller = "Site",
        action = "Index",
        id = UrlParameter.Optional
    }
);

我认为这将解决您的问题,但请确保我建议的自定义路由在默认路由之前。

更新:

您有一个 Get 方法和一个 Post 方法。

Get 方法(可能)创建一个视图模型对象,并将其发送到视图,视图呈现它。或者,您的视图可以在 HTML 中硬编码或通过 AJAX 调用注入各种输入。无论它们是如何到达那里的,发送到 Web 浏览器的渲染视图都如下所示:

<html>
<head />
<body>
<form>
<input id="Input1" ... />
<select id="Select1" ... />
</form>
</body>
</html>

以上是 HTML 的一个大大简化的结构。

输入的 ID 与回发此页面时将创建的视图模型对象(即 Registration 类的实例)中的属性名称匹配。

在返回(到 Post 方法)的途中,模型绑定程序从请求中获取值(查询字符串参数、表单值等),并将它们绑定回提供给 Post 方法的模型对象中。

在您的情况下,最有可能发生的事情是 Get 方法(和呈现的视图)中id的含义与id提供给 Post 方法的Registration对象中的含义不匹配。

不匹配的原因是Registration.Id属性名称由数据库指定,Create(string id)由默认路由决定,但它们实际上是不同的东西,因此应该以不同的方式命名。

这就需要有一个干净的/Create/id 表单 URL,这可以通过自定义路由轻松完成。

现在,如果您真的想从模型绑定逻辑中排除参数,那么您可以使用另一个答案,该答案使用 Post 方法的 Registration 参数上的属性来显式告诉DefaultModelBinder从绑定逻辑中排除该参数。

完成此操作后,它将绑定到的属性将保留 CLR 在实例化和运行构造函数后提供给它的默认值。

ASP.NET MVC 还支持自定义模型绑定器,如果需要,这些绑定程序可以显著更改模型绑定逻辑,但这不适用于您的情况。

尝试使用 BindAttribute

[HttpPost]
public ActionResult Create([Bind(Exclude = "RegistrationId")]Registration registration)
{ 
}

绑定到模型时,它将省略带有表单的RegistrationId POSTed...