简体   繁体   中英

System.ArgumentNullException: 'Value cannot be null. Parameter name: items'

This is my index.cshtml :

<div class="form-group">
@Html.LabelFor(model => model.MembershipID, "MembershipID", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
    @Html.DropDownList("items", new SelectList((IEnumerable<SelectListItem>)ViewData["MembershipID"]), new { @class = "form-control" })
    @Html.ValidationMessageFor(model => model.MembershipID, "", new { @class = "text-danger" })
</div>

This is my StudentController.cs :

public ActionResult Create()
{
    List<SelectListItem> items = new List<SelectListItem>();

    items.Add(new SelectListItem { Text = "Child", Value = "0" });

    items.Add(new SelectListItem { Text = "Teen", Value = "1" });

    items.Add(new SelectListItem { Text = "Adult", Value = "2" });

    items.Add(new SelectListItem { Text = "Other", Value = "3" });

    items.Add(new SelectListItem { Text = "check", Value = "4" });


    ViewData["MembershipID"] = items;

    return View();
}

Controller post method:

[HttpPost] 
public ActionResult Create(Student student) 
{ 
    try 
    { 
        // TODO: Add insert logic here 
        using (BlackBeardDBEntities db = new BlackBeardDBEntities()) 
        { 
            db.Students.Add(student); 
            db.SaveChanges(); 
        } 
        return RedirectToAction("Index"); 
    } 
    catch 
    { 
        return View(); 
    }
}

Update

From your comment below I can see you have this piece of code:

[HttpPost] 
public ActionResult Create(Student student) 
{ 
    ...
    return RedirectToAction("Index"); 
    ...
}

You are performing a redirect here. ViewData only lives for a single request, so what's happening is when the browser redirects to the Index action the ViewData is empty (because it was sent in the request which told the browser to redirect).

This is why you should not use ViewData for these types of task, use a ViewModel instead.

However, to solve your problem don't redirect. Just return the Index view straight from the Create POST method (remember the data must be passed to the view with each request, so you will need to populate ViewData["MembershipID"] again):

[HttpPost] 
public ActionResult Create(Student student) 
{ 
    ...
    // populate ViewData here, before returning the view
    ViewData["MembershipID"] = GetItems();
    return View("Index"); 
    ...
}

Create a method ( GetItems in my example, I'll leave the implementation details to you) to return the items since you use them in multiple places.

ViewData will be preserved in this request since it's returning straight to Index rather than performing a redirect.

From the above conversation, you could have your controller as follows

public class StudentsController : Controller
{

    private void _SetViewData()
    {
        List<SelectListItem> items = new List<SelectListItem>();
        items.Add(new SelectListItem { Text = "Child", Value = "0" });
        items.Add(new SelectListItem { Text = "Teen", Value = "1" });
        items.Add(new SelectListItem { Text = "Adult", Value = "2" });
        items.Add(new SelectListItem { Text = "Other", Value = "3" });
        items.Add(new SelectListItem { Text = "check", Value = "4" });
        ViewData["MembershipID"] = items;
    }

    // GET: Students
    public ActionResult Index()
    {
        // In case your index view uses viewdata, call _SetViewData() if  not remove.
        _SetViewData();
        return View();
    }

    // GET: Students/Create
    public ActionResult Create()
    {
        _SetViewData();
        return View();
    }

    [HttpPost]
    public ActionResult Create(Student student)
    {
        try
        { 
            // TODO: Add insert logic here 
            using (BlackBeardDBEntities db = new BlackBeardDBEntities()) 
            { 
                db.Students.Add(student); db.SaveChanges(); 
            }                 
            return RedirectToAction("Index"); 
        } 
        catch {
            // Either you can redirect to the action which will reload the viewdata
            // return RedirectToAction("Create");
            // OR you could load the viewdata and use the same view
            _SetViewData();
            return View();
        } 
    } 
}

Here, you may use a private method to set your viewdata needed for an action. If you are returning the view, call this method to set viewdata if not, redirect to Create action which will call the get action and sets the viewdata.

Hope this helps you.

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