【问题标题】:The ViewData item that has the key 'CategoryId' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'具有键“CategoryId”的 ViewData 项的类型为“System.Int32”,但必须为“IEnumerable<SelectListItem>”类型
【发布时间】:2015-02-05 10:08:00
【问题描述】:

我试图将一些新帖子保存到我的数据库中,但我反复遇到错误。我在下面有一个“Posts.cs”类

    public partial class Post
    {
        public Post()
        {
            this.Replies = new HashSet<Reply>();
        }

        public int PostId { get; set; }
        public string PostTitle { get; set; }
        public string PostContent { get; set; }
        public int AuthorId { get; set; }
        public int CategoryId { get; set; }
        public System.DateTime DateCreated { get; set; }

        public virtual Category Category { get; set; }
        public virtual UserProfile UserProfile { get; set; }
        public virtual ICollection<Reply> Replies { get; set; }
    }
}

还有一个 ViewModel,我用来为用户呈现视图以添加帖子

 public class AddPostsVM
    {
        [Display(Name = "CategoryId")]
        public int CategoryId { get; set; }

        [Required()]
        [Display(Name="Title")]
        public string PostTitle { get; set; }

        [Required()]
        [Display(Name="Content")]
        public string PostContent { get; set; }

        [Required()]
        [Display(Name="Select a Category")]
        public string CategoryName { get; set; }

        public List<SelectListItem>CategoriesList { get; set; }
    }

我使用视图模型渲染了一个视图,视图中有一个下拉列表,以获取数据库中的类别列表,这样当用户添加帖子时,他们可以选择他们希望帖子所属的类别

[HttpGet]
    public ActionResult CreatePost()
    {
        AddPostsVM model = new AddPostsVM();
        var categories = (from c in db.Categories
                         select new
                         {
                             CategoryName = c.CategoryName,
                             CategoryId = c.CategoryId
                         }).ToList();

        model.CategoriesList = categories.Select(c => new SelectListItem
        {
            Text = c.CategoryName,
            Value = c.CategoryId.ToString()

        }).ToList();


        return View(model);
    }

在我看来 CreatePost.cshtml 我有这个

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

    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.PostTitle, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.PostTitle, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.PostTitle, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.PostContent, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @*@Html.TextAreaFor(model => model.PostContent, new { htmlAttributes = new { @class = "form-control" } })*@
                <textarea class="form-control" name="PostContent" id="PostContent" rows="3"></textarea>
                @Html.ValidationMessageFor(model => model.PostContent, "", new { @class = "text-danger" })
            </div>
        </div>
                <div class="form-group">
            @Html.LabelFor(model => model.CategoryId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.CategoryId, Model.CategoriesList, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

每当我尝试使用下面的 Post 操作向数据库添加新帖子时

[HttpPost]
public ActionResult CreatePost(AddPostsVM model)
{
    try
    {
        if (ModelState.IsValid)
        {
            var newPost = db.Posts.Create();
            newPost.PostTitle = model.PostTitle;
            newPost.PostContent = model.PostContent;
            FormsIdentity identity = (FormsIdentity)User.Identity;
            int nUserID = Int32.Parse(identity.Ticket.UserData);
            newPost.AuthorId = nUserID;
            newPost.CategoryId = model.CategoryId;
            newPost.DateCreated = DateTime.Now;
            db.Posts.Add(newPost);
            db.SaveChanges();
            return RedirectToAction("Index", "Posts");
        }
        else
        {
            ModelState.AddModelError("", "Invalid Model");

        }

    }
    catch (DbEntityValidationException e)
    {
        foreach (var eve in e.EntityValidationErrors)
        {
            Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                 eve.Entry.Entity.GetType().Name, eve.Entry.State);
            foreach (var ve in eve.ValidationErrors)
            {
                Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                    ve.PropertyName, ve.ErrorMessage);
            }
        }
        throw;


    }
    return View(model);
}

我可以看到 ModelState.IsValid 正在返回 false 并且我收到错误消息

The ViewData item that has the key 'CategoryId' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.

请问我该如何解决?

【问题讨论】:

  • 也在 post 操作中初始化 model.CategoriesList。然后您可以看到验证错误。当 model.CategoriesList 为 null 时会出现您遇到的错误,在这种情况下,框架会尝试从 ViewData 读取列表,并且该值不是该错误消息中指定的预期类型。
  • @Matthew 我做到了,但我没有得到任何错误,除了我设置我自己,如果 modelstat 无效我应该得到“无效模型”。除此之外没有错误
  • @ibnhamza,当您返回视图时,model.CategoriesListnull,因此您会收到该错误。如果您返回视图,则必须重新分配 SelectList
  • @StephenMuecke 你能帮我用正确的代码重写代码。会欣赏的。从那以后一直在涉足。
  • @ibnhamza,在 POST 方法中,在 return View(model); 行之前,只需复制您在 GET 方法中用于分配model.CategoriesList 的代码,即var categories = ....; model.CategoriesList = .....;

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


【解决方案1】:

ModelState 总是返回 false 的原因是属性 CategoryName 具有 [Required] 属性,并且您不呈现控件并回发值,因此它始终为 null,因此无效。但是CategoryName 与与您下拉列表关联的选定类别相关,因此您应该删除此属性并仅依赖绑定到下拉列表的CategoryId

错误的原因是当您返回视图时(由于上述问题,这总是发生),您没有重新分配 CategoriesList 的值,因此它的 null@Html.DropDownListFor(model =&gt; model.CategoryId, Model.CategoriesList, ..) 抛出异常。

为避免重复,您可以将公共代码重新分解为私有方法(请注意,这假设您将 public List&lt;SelectListItem&gt; CategoriesList { get; set; } 更改为 public SelectList CategoriesList { get; set; }

private void ConfigureEditModel(AddPostsVM model)
{
  model.CategoriesList = new SelectList(db.Categories, "CategoryID", "CategoryName");
  // any other common stuff
}

您现在可以在 GET 方法和 POST 方法中调用它

[HttpGet]
public ActionResult CreatePost()
{
    AddPostsVM model = new AddPostsVM();
    ConfigureEditModel(model);
    return View(model);
}

[HttpPost]
public ActionResult CreatePost(AddPostsVM model)
{
  if (!ModelState.IsValid)
  {
    ConfigureEditModel(model); // repopulate select list
    return View(model); // return the view to correct errors
  }
  // Save and redirect
}

【讨论】:

    猜你喜欢
    • 2012-01-25
    • 2016-03-06
    • 2014-11-13
    • 2014-04-17
    • 2014-10-02
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多