【问题标题】:Invalid ModelState when moving items from one select list to another via javascript通过 javascript 将项目从一个选择列表移动到另一个选择列表时,ModelState 无效
【发布时间】:2011-06-21 03:15:14
【问题描述】:

我有一个页面,其中包含两个列表,一个为空,一个填充了值,两者的结构相同。用户可以从填充列表中选择一个项目,单击一个按钮,它将通过 jQuery 移动到空列表。提交表单后,我将所有选项 ID 保存到隐藏的表单字段中,以便稍后在发布后解析出来。但是,当我提交页面时,如果我将一个值从一个列表框移动到另一个,我会遇到以下错误(否则,页面正常发布):

System.InvalidOperationException: The parameter conversion from type 
'System.String' to type 'System.Web.Mvc.SelectListItem' failed because no type
 converter can convert between these types. at 
 System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType) at 
 System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType) at 
 System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture) at 
 System.Web.Mvc.ValueProviderResult.ConvertTo(Type type) at 
 System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)

以下是相关代码:

视图模型:

public class ViewModel
{
    public IEnumerable<SelectListItem> currentUsers { get; set; }
    public IEnumerable<SelectListItem> availableUsers { get; set; }
}

初始控制器动作:

public ActionResult Index() 
{
    IEnumerable<User> availableUsers = SomeDal.GetUsers();

    var model = new ViewModel 
    {
        currentUsers = Enumerable.Empty<User>().Select(x => new SelectListItem
        {
            Value = x.id.ToString(),
            Text = x.name
        }),

        availableUsers = availableUsers.Select(x => new SelectListItem
        {
            Value = x.id.ToString(),
            Text = x.lastName
        })
    };
}

POST 控制器动作:

[HttpPost]
public ActionResult Index(ViewModel model) 
{
    // at this point, ModelState.IsValid is already true, so I figure the rest of this isn't necessary
}

移动项目的jQuery:

$('#swapUsers').click(function () {
    $('#availableUsers option:selected').appendTo('#currentUsers');
});

列表框::

@Html.ListBox(
         "currentUsers",
         new SelectList(Model.currentUsers, "value", "text"),
         new { @class = "listbox" }
         )

@Html.ListBox(
         "availableUsers",
         new SelectList(Model.availableUsers, "value", "text"),
         new { @class = "listbox" }
         )

我一开始以为是因为我奇怪的 Enumerable.Empty 调用,但是即使 currentUsers IEnumerable 包含数据也会发生错误。

编辑 1:

HTML 预发布

<select class="listbox" id="currentUsers" multiple="multiple" name="currentUsers"></select>
<select class="listbox" id="availableUsers" multiple="multiple" name="availableUsers">
    <option value="1">Test User 1</option>
    <option value="2">TestUser2</option>
</select>

HTML 发布后

<select class="input-validation-error listbox" id="currentUsers" multiple="multiple" name="currentUsers">
    <option selected="selected" value="1">Test User 1</option>
</select>
<select class="listbox" id="availableUsers" multiple="multiple" name="availableUsers">
    <option value="2">TestUser2</option>
</select>

【问题讨论】:

  • 嗯。我认为如果您提供 2 个列表的 HTML 内容以及该错误消息的堆栈跟踪,将会很有帮助。

标签: asp.net-mvc


【解决方案1】:

请记住,提交表单时发布到服务器的模型将仅包含选定值的列表;您没有显示/说,但听起来您提交的操作正在接受与您用于显示表单的 ViewModel 相同的 ViewModel。 ViewModel 类的每个属性都有 IEnumerable ,您得到的错误是因为 ModelBinder 无法将字符串列表转换为 IEnumerable (或 IEnumerable ...对这种差异有点困惑; 也许您的模型传入(或参数)到该方法有一个 IEnumerable?)。

真的,表单提交应该有一个模型接受两个列表(或者实际上它可能只需要 currentUsers 列表)作为整数列表(或任何实际类型)。

public ActionResult PostMethod(IEnumerable<int> currentUsers)
{
    ...
}

【讨论】:

  • (模型中的我的 IEnumerable 应该是 IEnumerable;错字。)我的提交操作采用相同的 ViewModel,它还包含两个存储用户 ID 的 IEnumerable。这些是通过解析隐藏字段来填充的(由 jQuery 在表单提交时创建);但是,一旦我输入提交操作,我的 ModelState 就无效了,所以我认为之后的任何内容都不相关?
  • MVC 正在尝试为您填充模型。我认为克里斯所说的是准确的。
  • 如果是这样,那么为什么表单在正常提交时可以完美运行?当我使用我的小 javascript 函数将项目从一个列表移动到另一个列表时,它只会引发错误。这是我不太明白的一点。
  • 其实稍微想了想,一个SelectList只会尝试提交选中的项目,它甚至不会为列表中未选中的项目提交值。我猜您的“正常提交”测试不包含任何列表中的任何选定项目 - 这是因为模型绑定器没有任何数据可以绑定到这些属性。您的 JS 在至少一个列表中选择了一个项目,然后将其发布到服务器并且由于属性类型不正确而无法绑定。
  • 将 ViewModel 传递给帖子不一定是问题;问题是您有一个IEnumerable&lt;SelectListItem&gt; 类型的属性,它与正在发布的属性同名。这可以通过两种方式解决 - 1) 不要发布与选择列表项同名的任何内容或 2) 使用不同的模型发布。 #2 可能是更“正确”的方法,但这意味着可能不需要额外的代码(从这个距离很难说:))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
相关资源
最近更新 更多