ASP.NET Core MVC使用ExpandoObject传多模型分部视图类型报错
异常原因
异常由两个问题直接导致:
- 分部视图传参规则:在视图中调用
<partial>标签时,如果不显式指定model参数,框架会自动将当前视图的母模型作为参数传入分部视图。当前Details视图的母模型是System.Dynamic.ExpandoObject类型,而Comments分部视图声明的强类型为MyProject.Models.Comments,类型不匹配直接抛出InvalidOperationException。 - 现有控制器代码未向动态模型中添加Comments相关数据,即便传参逻辑正确,也拿不到对应的模型对象。
正确实现方案
第一步:修改控制器Details方法,补充Comments数据
如果分部视图用于提交评论,传入绑定了当前食谱ID的空Comments实例即可;如果需要展示已有评论,额外查询对应食谱的评论列表赋值到动态模型:
public ViewResult Details(int id) { dynamic mymodel = new ExpandoObject(); var det = _recepie.Recepies.Find(id); var user = _usr.Users.Find(det.UserId); // 初始化评论对象,绑定当前食谱ID var newComment = new MyProject.Models.Comments() { RecepieId = id }; // 如需展示已有评论列表,解开下面注释 // var commentList = _cmnt.Comments.Where(c => c.RecepieId == id).ToList(); mymodel.Recepie = det; mymodel.User = user; mymodel.Comment = newComment; // mymodel.CommentList = commentList; return View(mymodel); }
第二步:修改Details视图的分部视图调用代码
调用partial标签时显式传入Comments类型的模型,禁止框架默认传递ExpandoObject母模型:
@model dynamic @{ Layout="_RecepieLayout"; } <div class="row"> <div class="col-md-5 col-sm-12" > <img src="~/Images/fishsoup.jpg" style="max-width:500px;"/> </div> <div class="col-md-7"> <h1> @Model.Recepie.Category </h1> <p> @Model.Recepie.name </p> <p> 创建者:@Model.User.name </p> <p> @Model.Recepie.Description </p> <p> @Model.Recepie.Ingredients </p> </div> </div> @* 关键修改:显式指定传入分部视图的模型 *@ <partial name="Comments" model="Model.Comment" /> @* 如果要渲染评论列表,将分部视图@model改为IEnumerable<MyProject.Models.Comments>,此处传Model.CommentList即可 *@
可选优化:使用强类型视图模型替代ExpandoObject
ExpandoObject属于动态类型,编译阶段无法检查类型错误,线上更容易出问题,更规范的做法是自定义专用视图模型:
- 新建视图模型类
// 路径建议:ViewModels/RecepieDetailsViewModel.cs namespace MyProject.ViewModels { public class RecepieDetailsViewModel { public Recepie Recepie { get; set; } public User User { get; set; } public Comments Comment { get; set; } public IEnumerable<Comments> CommentList { get; set; } } }
- 控制器改用强类型视图模型
public ViewResult Details(int id) { var det = _recepie.Recepies.Find(id); var user = _usr.Users.Find(det.UserId); var viewModel = new RecepieDetailsViewModel { Recepie = det, User = user, Comment = new Comments { RecepieId = id }, CommentList = _cmnt.Comments.Where(c => c.RecepieId == id).ToList() }; return View(viewModel); }
- Details视图顶部修改模型声明,其余代码无需变动
@model MyProject.ViewModels.RecepieDetailsViewModel
内容的提问来源于stack exchange,提问作者ARSH AHMAD
相关产品推荐
相关产品推荐

