简体   繁体   中英

“Index was out of range” error in asp.net MVC project

I'm working on asp.net MVC 5 project.I have two models Post and Comment having one to many relationship between them. In Post's Details view, I want to add comments in that Post. How can I do it without using any ViewModel? Only Post model is passed in the view. I want to access Comment and its properties by using Post model reference, after all they have one many relationship between them, Post model have Comment's reference.

Here is my code example Details actions in Post's controller

    [HttpPost]
    public ActionResult Details(Comment comment, string post_id)
    {
        int id = int.Parse(post_id); 

        if (ModelState.IsValid)
        {


            var post = db.Posts.FirstOrDefault(u => u.id == id);



            comment.post = post;

            db.Comments.Add(comment);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(comment);
    }
    //
    // GET: /Post/Details/5

     public ActionResult Details(int id = 0)
     {
         Post post = db.Posts.Find(id);
         if (post == null)
         {
             return HttpNotFound();
         }
         return View(post);
     }

here is Details.schtml

  @model Blog.Models.Post

@{
ViewBag.Title = "Details";
}

  <h2>Details</h2>

<fieldset>
<legend>Post</legend>

<div class="display-label">
     @Html.DisplayNameFor(model => model.title)
</div>
<div class="display-field">
    @Html.DisplayFor(model => model.title)
</div>

<div class="display-label">
     @Html.DisplayNameFor(model => model.body)
</div>
<div class="display-field">
    @Html.DisplayFor(model => model.body)
</div>

@for (int i = 0; i <Model.comments.Count; i++)
{

     <div class="display-label">
     @Html.DisplayNameFor(model => model.comments[i].comment)
</div>

<div class="display-field">
    @Html.DisplayFor(model => model.comments[i].comment)

</div>
}

<h2>Comment</h2>

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

    <fieldset>
        <legend>Article</legend>

        <div class="editor-label">


            @Html.LabelFor(model =>model.comments[Model.comments.Count].comment)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model =>model.comments[Model.comments.Count].comment))
            @Html.ValidationMessageFor(model => model.comments[Model.comments.Count].comment)
        </div>


        <p>
            <input type="submit" value="Add" />
        </p>
    </fieldset>
}

  </fieldset>

There is an error

"Index was out of range. Must be non-negative and less than the size of the collection.\\r\\nParameter name: index"

how can I successfully add comments ?

The error itself pretty much explains the problem. On the line where you get the error the Model.comments.Count is out of the range. The indexation starts from 0 so the last comment should be retrieved this way .... model => model.comments[Model.comments.Count - 1].comment .

Your exception is generated by the following line in your view

@Html.LabelFor(model =>model.comments[Model.comments.Count].comment)

and will also be generated by the subsequent EditorFor() and ValidationMessageFor() methods.

Collection indexers are zero based, whereas .Count() returns the number of items in the collection. If say you collection contained 2 Comment , then you would access them as

model.Comments[0].comment
model.Comments[1].comment

but your [Model.comments.Count] equates to

model.Comments[2].comment

which throws the exception because your referring to the 3rd item in the collection (which does not exist). Even if you referred to an existing item in the collection, you code would fail because you would be posting back a collection (defined by the indexer) but you POST method only excepts a single object

It appears you wanting to add a new comment to the Post in which case you can either use a view model containing an additional property for Comment

public Comment NewComment { get; set; }

and then in you view, generate the form controls using

@Html.EditorFor(m => m.NewComment.comment)

and change the POST method signature to

public ActionResult Details([Bind(Prefix = "NewComment")]Comment comment, int post_id)

Note the use of the Bind.Prefix property which is necessary to strip the "NewComment" prefix from the name/value pair posted to the method. Note also that you can make the second parameter int and avoid the unnecessary conversion from string to int (although you do not appear to be generating a form control for property post_id so it will be null anyway).

An alternative would be to use @Html.Action() to call a child action method that returns a partial view (containing the form) based on a new Comment .

It is because of db.Posts.Find(id); . you have given initial value for id in public ActionResult Details(int id = 0) . Check your code to be sure you always pass value to id.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM