You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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丢失的原因:

  1. 表单字段名和Action参数名不匹配:表单movieTitle对应Action的titleSearch,movieGenre对应genreSearch,参数名不一致导致Action接收到空值,再存到ViewData["titleSearch"]后,View里的input又用@ViewData["movieTitle"]取值,双重不匹配自然显示为空。
  2. Search Action里没有重新设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:37:59