ASP.NET MVC Layout.cshtml调用模型报类型不匹配错误解决方法
报错核心原因
- Layout.cshtml是全站复用的共享布局页,默认继承当前访问视图传入的Model对象。你直接给Layout声明强类型为
IEnumerable<SelectListItem>后,只要任意引用该布局的视图传入的Model不是这个类型(比如传入自定义ViewModel的场景),就会抛出你看到的类型不匹配异常。 - 当前代码只在Index Action中把下拉列表数据传递给Index视图,Layout没有稳定的公共数据获取渠道,给共享布局页绑定固定强类型模型的思路本身就不成立——毕竟不同页面的视图模型类型不可能完全一致。
正确实现步骤
1. 移除Layout的强类型模型声明
直接删掉Layout.cshtml顶部的@model IEnumerable<SelectListItem>代码,避免固定类型和其他页面的Model冲突。
2. 统一加载Layout需要的公共下拉数据
因为下拉列表是Layout要用到的公共数据,不需要每个Action单独传递,推荐用全局过滤器统一加载,一次实现所有页面自动可用:
- 新建公共数据加载过滤器
public class CommonDataFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { // 仅在返回视图结果时加载公共数据,避免接口请求、重定向请求重复执行 if (filterContext.Result is ViewResult viewResult) { var subSections = UtilityResource.GetSubSections().Result; var subSectionList = subSections.Select(c => new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }).OrderBy(c => c.Text).ToList(); filterContext.Controller.ViewBag.SubSectionList = subSectionList; } base.OnActionExecuted(filterContext); } }
- 在
App_Start/FilterConfig.cs中注册全局过滤器,注册后所有Action执行完成后都会自动加载这份下拉数据,无需在每个业务Action中重复编写加载逻辑
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CommonDataFilter()); // 保留原有全局过滤器配置,比如HandleErrorAttribute } }
如果下拉列表只需要在特定模块的Layout中使用,不需要全局加载,可以把上述加载逻辑写到自定义Controller基类的
OnActionExecuted方法中,让对应模块的Controller继承该基类即可。
3. 修改Layout中的下拉列表渲染代码
直接从全局ViewBag中读取数据渲染,不再依赖强类型Model:
<select id="subSectionID"> @foreach (var item in (IEnumerable<SelectListItem>)ViewBag.SubSectionList) { <option value="@item.Value">@item.Text</option> } </select>
4. 调整Index页相关逻辑适配ViewModel
如果你Index页需要使用自定义的ViewModel,修改Index Action返回ViewModel对象,不要直接返回SelectListItem列表:
public async Task<ActionResult> Index() { var subSections = await UtilityResource.GetSubSections(); var subSectionList = subSections.Select(c => new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }).OrderBy(c => c.Text).ToList(); var viewModel = new ViewModel { SubSections = subSectionList, // 为ViewModel的其他属性赋值,比如SelectedSubSectionId、VisitVMList、SubSectionName }; return View(viewModel); }
对应修改Index.cshtml顶部的模型声明,页面内如果需要渲染下拉列表,直接读取Model.SubSections即可,不会和Layout的渲染逻辑冲突。
内容的提问来源于stack exchange,提问作者Michaelweston
相关产品推荐
相关产品推荐

