MVC模式状态验证列表框上的失败 [英] MVC Model State Validation fails on Listbox

查看:164
本文介绍了MVC模式状态验证列表框上的失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的系统使用多选列表框为多对多的关系EF一个简单的模型。

I have a simple model which uses a multi select listbox for a many-many EF relationship.

在我的创建行动,我得到了错误

On my Create action, I'm getting the error

从类型'System.String'输入'MyProject.Models.Location的参数转换失败,因为没有类型转换器可以将这些类型之间的转换。

The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.

我有2个型号,文章和地点:

I have 2 models, an Article and a Location:

Article.cs

Article.cs

namespace MyProject.Models
{
    public class Article
    {
        public Article()
        {
            Locations = new List<Location>();
        }

        [Key]
        public int ArticleID { get; set; }

        [Required(ErrorMessage = "Article Title is required.")]
        [MaxLength(200, ErrorMessage = "Article Title cannot be longer than 200 characters.")]
        public string Title { get; set; }

        public virtual ICollection<Location> Locations { get; set; }
    }

Location.cs:

Location.cs:

namespace MyProject.Models
{
    public class Location
    {
        [Key]
        public int LocationID { get; set; }

        [Required(ErrorMessage = "Location Name is required.")]
        [MaxLength(100, ErrorMessage = "Location Name cannot be longer than 100 characters.")]
        public string Name { get; set; }

        public virtual ICollection<Article> Articles { get; set; }
    }
}

我有一个视图模型:

I have a ViewModel:

namespace MyProject.ViewModels
{
    public class ArticleFormViewModel
    {
        public Article article { get; set; }
        public virtual List<Location> Locations { get; set; }

        public ArticleFormViewModel(Article _article, List<Location> _locations)
        {
            article = _article;
            Locations = _locations;
        }
    }
}

create.cshtml:

create.cshtml:

@model MyProject.ViewModels.ArticleFormViewModel
<h2>Create</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Article</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.article.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.article.Title)
            @Html.ValidationMessageFor(model => model.article.Title)
        </div>
        <h3>Locations</h3>
        @Html.ListBoxFor(m=>m.article.Locations,new MultiSelectList(Model.Locations,"LocationID","Name"))
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

最后我控制器操作:

Finally my controller actions:

// GET: /Article/Create

public ActionResult Create()
{

    var article = new Article();
    var AllLocations = from l in db.Locations
                      select l;

    ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());

    return View(viewModel);


}

//
// POST: /Article/Create

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Article article)
{
    var errors = ModelState.Values.SelectMany(v => v.Errors);

    if (ModelState.IsValid)
    {
        var locations = Request.Form["article.Locations"];
        if (locations != null)
        {
            var locationIDs = locations.Split(',');
            foreach (var locationID in locationIDs)
            {
                int id = int.Parse(locationID);
                Location location = db.Locations.Where(l => l.LocationID == id).First();
                article.Locations.Add(location);
            }
        }

        db.Articles.Add(article);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    var AllLocations = from l in db.Locations
                       select l;
    ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());
    return View(viewModel);

}

这所有的作品比较好,我的位置列表框正确填充:

This all works relatively well, my Locations listbox is populated properly:

如果我不选择一个位置,然后我的模型正确保存。如果我选择一个或多个位置,然后我Model.IsValid检查失败与例外

If I do not select a Location then my model is saved properly. If I select one or more locations then my Model.IsValid check fails with the exception

从类型'System.String'输入'MyProject.Models.Location的参数转换失败,因为没有类型转换器可以将这些类型之间的转换。

The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.

但是,如果我删除ModelState.IsValid检查则尽管我值都正确保存到数据库中的错误 - 只是我失去的东西验证,如模型标题

However if I remove the ModelState.IsValid check then despite the error my values are all correctly saved into the database - just that I lose validation for things such as the model title.

希望有人能帮助!

推荐答案

除非你创建一个类型转换,你不能直接您的列表框中的结果直接绑定到这样一个复杂的对象。其原因在于以下事实的MVC只能处理张贴的HTTP值,在此情况下是包含选定的ID字符串数组。这些字符串不直接映射到位置对象(即数字1不能直接转换为位置为1的ID对象)。

Unless you create a type converter, you cannot directly bind the results of your list box directly to a complex object like that. The reason lies in the fact that MVC can only deal with posted HTTP values, which in this case are an array of strings that contain the selected ID's. Those strings do not directly map to your Locations object (ie the number 1 cannot be directly converted to a Locations object with an ID of 1).

您最好的选择是有位置的ID名单中的字符串类型的视图模型或INT接受贴出值,那么在您的文章的方法创建对象的位置,并用正确的ID的填充。

Your best bet is to have a list of location ID's in your View Model of type string or int to accept the posted values, then in your post method create the Location objects and fill them with the correct ID's.

仅供参考,您的code工作的原因是因为你绕过模型绑定,并直接到Request.Form集合。你会发现,绑定对象条将不会有任何位置的物体。

FYI, the reason your code works is because you are bypassing the model binding and going directly to the Request.Form collection. You will notice that the bound Article object will not have any Location objects.

编辑:

我甚至不看你的code甚至会工作,没有这个问题。您ArticleFormViewModel没有参数的构造函数,这样,会在模型绑定失败(除非你有一个自定义模型粘合剂)。

I don't even see how your code would work even without this problem. Your ArticleFormViewModel does not have a parameterless constructor, so that will fail in model binding (unless you have a custom model binder).

在任何情况下,你想要做的这是什么(请注意,您必须填充SelectedLocationIDs,如果你希望在视图呈现他们被选中):

In any event, what you want to do is this (note, you will have to populate SelectedLocationIDs if you want them to be selected when the view is rendered):

public class ArticleFormViewModel
{
    ...
    List<int> SelectedLocationIDs { get; set; }
    ...
}

然后,在你认为你有:

Then, in your view you have:

@Html.ListBoxFor(m=>m.SelectedLocationIDs, 
    new MultiSelectList(Model.Locations,"LocationID","Name"))

在安置自己的方法,而不是code调用的Request.Form,你有这样的事情:

In your Post method, instead of the code that calls Request.Form, you have something like this:

foreach(var locationID in article.SelectedLocationIDs) {
    ... // look up your locations and add them to the model
}

这篇关于MVC模式状态验证列表框上的失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆