AspNet Core下拉列表绑定问题:分部视图正常但控制器执行异常
Let's break down the issue you're facing and walk through the fixes step by step.
What's Causing the Exception?
From your description, there are two likely culprits:
- Incorrect
asp-itemsBinding: You're passing a list ofShortInfodirectly toasp-items, which expects anIEnumerable<SelectListItem>. While ASP.NET Core might do an implicit conversion in some cases, this can lead to inconsistent behavior and binding issues. - Model Binding Tries to Hydrate
InfoList: When you submit the form, the model binder attempts to populate the entireSelectSomethingmodel—including theInfolist ofShortInfoobjects. SinceShortInfohas read-only properties and no parameterless constructor, the binder can't instantiate newShortInfoinstances, triggering an exception.
Step 1: Correct the Dropdown List Binding
First, explicitly convert your ShortInfo list to a SelectList (or List<SelectListItem>) to ensure the dropdown works reliably. This makes the binding logic clear and avoids implicit conversion quirks.
Update your partial view code like this:
@model SelectSomething <div class="form-group"> <label asp-for="Id" class="control-label">Select an Item</label> <select asp-for="Id" class="form-control" asp-items="@new SelectList(Model.Info, nameof(ShortInfo.Id), nameof(ShortInfo.FullName))"> <option value="">-- Choose an option --</option> </select> <span asp-validation-for="Id" class="text-danger"></span> </div>
This explicitly tells the framework to use ShortInfo.Id as the option value and ShortInfo.FullName as the display text.
Step 2: Prevent Model Binding for the Info List
Since you only need the selected Id in your controller (not the entire Info list), we need to tell the model binder to ignore the Info property during POST requests. You have two clean ways to do this:
Option A: Use the [BindNever] Attribute
Add the [BindNever] attribute to the Info property in your SelectSomething class. This instructs the model binder to skip binding this property entirely:
using Microsoft.AspNetCore.Mvc.ModelBinding; public class SelectSomething { public int Id { get; set; } [BindNever] public List<ShortInfo> Info { get; set; } }
Option B: Use a ViewModel for Separation of Concerns
For a more robust approach (especially if your application grows), create a dedicated view model that separates display data from bindable data:
// ViewModel for displaying the dropdown public class SelectSomethingViewModel { public int SelectedItemId { get; set; } public List<ShortInfo> ItemOptions { get; set; } } // Your existing domain classes remain unchanged public class ShortInfo { public int Id { get; } public string FullName { get; } public ShortInfo(int id, string fullName) { Id = id; FullName = fullName; } }
Update your partial view to use this view model:
@model SelectSomethingViewModel <div class="form-group"> <label asp-for="SelectedItemId" class="control-label">Select an Item</label> <select asp-for="SelectedItemId" class="form-control" asp-items="@new SelectList(Model.ItemOptions, nameof(ShortInfo.Id), nameof(ShortInfo.FullName))"> <option value="">-- Choose an option --</option> </select> <span asp-validation-for="SelectedItemId" class="text-danger"></span> </div>
Then in your controller, handle GET and POST requests separately:
// GET: Populate the view model with options public IActionResult LoadPartial() { var viewModel = new SelectSomethingViewModel { ItemOptions = GetShortInfoItems() // Replace with your data retrieval logic }; return PartialView("_YourPartialViewName", viewModel); } // POST: Only accept the selected ID [HttpPost] public IActionResult ProcessSelection(int selectedItemId) { // Handle the selected ID here return RedirectToAction("Index"); }
Why This Works
- The explicit
SelectListconversion ensures the dropdown renders correctly with the right value/text pairs. - By ignoring the
Infolist (either via[BindNever]or a view model), we avoid the model binder trying to instantiate read-onlyShortInfoobjects during POST, eliminating the exception.
内容的提问来源于stack exchange,提问作者Luca Mori

