ASP.NET Core 3.1 MVC传递模型至Action时415状态码问题求助
我来帮你梳理下问题,你遇到的两个核心问题:415错误和搜索后字段清空,其实都是模型绑定和数据回显没做好导致的,咱们一步步解决:
一、为什么传Movies模型会报415错误?
HttpGet请求下,ASP.NET Core的模型绑定是从URL查询字符串(也就是表单提交的键值对)匹配模型属性的。你的View里表单字段是movieTitle、movieGenre,但Movies实体的属性应该是Title、Genre——名字不匹配,绑定器找不到对应属性,就会抛出415错误(本质是无法将请求数据绑定到模型,被框架判定为媒体类型不匹配)。
更关键的是:你的View模型是IEnumerable<MyApp.Models.Movies>(电影列表),但你想把单个Movies对象作为Action参数,逻辑本身就不对——搜索条件是单个筛选值,视图模型是结果列表,两者不能混为一谈。
二、解决字段清空的核心:回显搜索条件和分页ID
你现在搜索后输入框、下拉框清空,隐藏pageID丢失的原因:
- 表单字段名和Action参数名不匹配:表单
movieTitle对应Action的titleSearch,movieGenre对应genreSearch,参数名不一致导致Action接收到空值,再存到ViewData["titleSearch"]后,View里的input又用@ViewData["movieTitle"]取值,双重不匹配自然显示为空。 SearchAction里没有重新设置ViewBag.pageID,返回视图时这个值为空,隐藏框自然没内容。
三、具体解决步骤
1. 创建搜索ViewModel(推荐方案,逻辑更清晰)
专门封装搜索条件、分页ID、下拉选项和结果列表,避免和实体模型混淆:
public class MovieSearchViewModel { public int PageID { get; set; } public string TitleSearch { get; set; } public string GenreSearch { get; set; } public SelectList GenreOptions { get; set; } public IEnumerable<Movies> MovieList { get; set; } }
2. 修正Controller的Action
Index Action(页面首次加载)
[HttpGet] [Route("/MoviesList/Index/{id}")] // 修正路由占位符写法,之前的id没加{}无法接收参数 public async Task<IActionResult> Index(int id) { var genres = await _db.Genres.ToListAsync(); var vm = new MovieSearchViewModel { PageID = id, GenreOptions = new SelectList(genres, "ID", "Genre"), MovieList = await _db.Movies.Where(x => x.Id == id).ToListAsync() }; return View(vm); }
Search Action(处理搜索请求)
[HttpGet] public async Task<IActionResult> Search(MovieSearchViewModel vm) { // 重新加载下拉选项并设置选中项,确保回显正确 var genres = await _db.Genres.ToListAsync(); vm.GenreOptions = new SelectList(genres, "ID", "Genre", vm.GenreSearch); // 构建查询逻辑 var query = _db.Movies.Where(x => x.Id == vm.PageID).AsQueryable(); // 空值检查,避免空引用异常 if (!string.IsNullOrEmpty(vm.TitleSearch)) { query = query.Where(x => x.Title.Contains(vm.TitleSearch)); } if (!string.IsNullOrEmpty(vm.GenreSearch)) { query = query.Where(x => x.Genre.Contains(vm.GenreSearch)); } vm.MovieList = await query.AsNoTracking().ToListAsync(); // 返回Index视图并传递ViewModel,所有数据自动回显 return View("Index", vm); }
3. 修正View代码
把View的模型改成MovieSearchViewModel,用asp-for标签助手自动完成绑定和回显:
@model MyApp.Models.MovieSearchViewModel @{ ViewData["Title"] = "Movies"; } <form method="get" role="form" asp-controller="MoviesList" asp-action="Search"> <!-- 隐藏分页ID,自动绑定ViewModel的PageID --> <input type="hidden" asp-for="PageID" /> <label>Movie Genre</label> <!-- 下拉框自动绑定选项和选中值 --> <select asp-for="GenreSearch" asp-items="@Model.GenreOptions"></select> <label>Movie Title</label> <!-- 搜索框自动回显输入内容 --> <input type="search" asp-for="TitleSearch" /> <input type="submit" value="Search" /> </form> <table> <thead> <tr> <th>@Html.DisplayNameFor(m => m.MovieList.First().Title)</th> <th>@Html.DisplayNameFor(m => m.MovieList.First().Genre)</th> </tr> </thead> <tbody> @foreach(var item in Model.MovieList) { <tr> <td>@Html.DisplayFor(modelItem => item.Title)</td> <td>@Html.DisplayFor(modelItem => item.Genre)</td> </tr> } </tbody> </table>
关键细节说明
asp-for标签助手会自动生成正确的name和value属性,既保证模型绑定不出错,又自动回显用户输入的内容。- 用ViewModel封装所有页面需要的数据,避免
ViewBag/ViewData的混乱,逻辑更清晰。 - 修正路由写法:之前的
[Route("/MoviesList/Index/id")]是错误的,必须用{id}作为路由参数占位符才能正确接收分页ID。
按照上面的步骤修改后,你就能实现搜索后字段不保留、可多次搜索的需求了。
内容的提问来源于stack exchange,提问作者Bee Swift
相关产品推荐
相关产品推荐

