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

标签 c# asp.net-mvc asp.net-mvc-4

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

我有一个修改版本的自动脚手架 “创建”(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 创建操作,则 ModelState.isValidPOST create 操作中为 false,因为它试图填充该值在 POST 操作中传递给 GET 操作的模型的主键 (Id) 字段(应该省略,因为它是自动生成的。

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

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

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

最佳答案

我认为您正在尝试做的是使用它应该创建的对象类型的 ID 参数化 Controller 的 Create 方法。

虽然在 ASP.NET MVC 中没有关于参数名称的硬性约定,但我认为大多数人都希望名为 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 方法(可能)创建一个 View 模型对象并将其发送到 View , View 呈现它。或者,您的 View 可以在 HTML 中硬编码或通过 AJAX 调用注入(inject)各种输入。不管他们是如何到达那里的,您在网络浏览器上呈现的 View 看起来像这样:

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

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

输入的 ID 与将在回发此页面时创建的 View 模型对象中的属性名称相匹配,即 Registration 类的实例。

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

在您的情况下,很可能发生的事情是 id 在 Get 方法(和呈现的 View )中的含义与 id 的含义不匹配在给 Post 方法的 Registration 对象中表示。

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

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

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

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

ASP.NET MVC 还支持自定义模型绑定(bind)器,如果需要,它们可以显着改变模型绑定(bind)逻辑,尽管这不适用于您的情况。

关于c# - ModelState.isValid 为假,因为 Id 模型属性与传递的参数冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14467605/

相关文章:

c# - MAPI 适用于一个 x64 系统,但不适用于另一个

asp.net - ASP.NET MVC5+ 中 "exists"路由约束的文档在哪里?

asp.net-mvc - @Html.ValidationMessageFor 检查是否为空

c# - 使用强类型 HTML 助手的 POST 上的 ASP MVC2 模型绑定(bind)问题

C#:如何在备忘录中添加一行?

c# - 实体与 Entity Framework 之间的复杂关系

c# - 你如何在 asp.net-mvc 中连接 Application_BeginRequest()

asp.net-mvc - 在非侵入式适配器期间使用 jQuery .ajax 进行验证

entity-framework - Entity Framework 映射问题

asp.net-mvc - 如何在 ASP.NET MVC 4 中忽略特定 View 文件夹或特定 cshtml 文件的路由