ASP.Net Core Razor Page向分部视图传自定义对象是否需单独ViewModel?
你当前使用自定义ViewModel封装数据后传递给分部视图的方案完全合理,并未违反Razor Pages的设计规范。
所谓「PageModel可直接充当ViewModel无需额外定义」的适用场景是主页面渲染,并非要求所有场景都不能定义ViewModel。针对分部视图抽取专用的ViewModel属于业内通用做法,具备类型安全、可复用、易维护的优势,没有任何问题。
方案1:直接传递整个PageModel给分部视图
如果该分部视图仅服务于当前页面,无需复用到其他页面,不需要额外封装ViewModel,直接传递完整的PageModel对象即可:
主页面调用代码
@page "{Id:int}" @model MyApp.Web.CreateModel <partial name="_myPartial" model="Model" />
分部视图代码
@model MyApp.Web.CreateModel // 直接使用 Model.myPerson、Model.selectListOne、Model.selectListTwo 渲染即可
该方案优势是无额外代码、实现最简,劣势是分部视图和当前页面的PageModel强绑定,无法复用到其他页面。
方案2:通过ViewData传递多参数
如果不想额外定义ViewModel,也可以通过ViewDataDictionary传递额外的参数,主页面的PageModel不需要定义myViewModel属性:
PageModel代码
[BindProperty] public Person myPerson { get; set; } public SelectList selectListOne { get; set; } public SelectList selectListTwo { get; set; } public IActionResult OnGet() { myPerson = new Person { Name = "", Date = DateTime.Now }; selectListOne = new SelectList(Enumerable.Range(0, 1000).ToList()); selectListTwo = new SelectList(Enumerable.Range(0, 1000).ToList()); return Page(); }
主页面调用代码
<partial name="_myPartial" model="Model.myPerson" view-data='new ViewDataDictionary { {"List1", Model.selectListOne}, {"List2", Model.selectListTwo} }' />
分部视图代码
@model Person @{ var selectListOne = ViewData["List1"] as SelectList; var selectListTwo = ViewData["List2"] as SelectList; }
该方案优势是不需要额外定义ViewModel类,劣势是没有类型安全校验,参数名称拼写错误只会在运行时报错,适合仅临时使用、复用度极低的场景。
方案3:使用View Component替代分部视图
如果该模块逻辑较为复杂、后续需要在多个页面复用,建议直接使用ASP.NET Core自带的View Component替代普通分部视图,它自带独立的逻辑处理层,不需要依赖主页面的PageModel:
ViewComponent类代码
public class PersonFormViewComponent : ViewComponent { public IViewComponentResult Invoke() { var viewModel = new viewModel { vmPerson = new Person { Name = "", Date = DateTime.Now }, vmselectListOne = new SelectList(Enumerable.Range(0, 1000).ToList()), vmselectListTwo = new SelectList(Enumerable.Range(0, 1000).ToList()) }; return View(viewModel); } }
组件视图代码和你当前的分部视图完全一致,主页面调用代码
@await Component.InvokeAsync("PersonForm")
该方案优势是逻辑完全独立、复用性极强,数据查询和组装逻辑不需要在主页面的PageModel中处理;劣势是需要额外创建ViewComponent类,仅单次使用的场景会显得冗余。
- 若分部视图仅在当前页面使用,优先选方案1,实现成本最低
- 若分部视图需要复用到多个页面,优先保留你当前的自定义ViewModel方案,类型安全、可维护性更高
- 若该模块后续需要独立的业务逻辑(如下拉选项从数据库读取、有独立的参数校验逻辑),优先选方案3的View Component,长期维护成本更低
内容的提问来源于stack exchange,提问作者tcode

