控制器重复调用ViewModel时,其构造函数会清空其他值吗?
问题描述
我曾尝试搜索该问题的答案,但只找到向Controller传递数据相关的内容,并非我所问的问题。如果Stack Overflow上已有相关答案,请告知我。
- 我们的ViewModel包含一个InventoryIn类实例作为属性。
- 我们希望重复调用同一视图,将ViewModel传回该视图。我们在视图中填充了InventoryIn的数据,但第二次调用时,InventoryIn实例变为空。
- 我能想到的唯一解释是InventoryIn的构造函数(我们在其中初始化了一些属性)。因此我的问题是:在Controller中重复向同一视图传递ViewModel时,ViewModel的构造函数是否总会被调用?我们原本认为不会,但可能有误。
另外,视图结构包含两个<form>标签:一个按钮提交到同一视图,调用视图首次加载时使用的同一Action方法;另一个<form>标签的Action方法提交到同一Controller下的另一个视图。
补充代码:控制器Action方法
public IActionResult Step1() { var newSiteToSite = new SiteToSite(); //do stuff here with newSiteToSite return View(newSiteToSite); } [HttpPost] [ValidateAntiForgeryToken] public IActionResult Step2(SiteToSite SiteToSite) { // THIS COULD BE COMING FROM STEP 1 OR STEP 2 if (Step1IsValid(SiteToSite)) { RefreshSiteToSite(SiteToSite); // RETURN STEP 2 VIEW return View("Step2", SiteToSite); // STEP 1 IS INVALID } else { // RETURN STEP 1 VIEW return View("Step1", SiteToSite); } }
RefreshSiteToSite方法
private void RefreshSiteToSite(SiteToSite siteToSite) { SetOriginatingLocation(siteToSite); SetDestinationLocation(siteToSite); int invOutItemPackageReceiptId = siteToSite.InvOutItemPackageReceiptID; GetSiteToSiteById(siteToSite, invOutItemPackageReceiptId); }
SetOriginatingLocation方法
private void SetOriginatingLocation(SiteToSite siteToSite) { var originatingLocation = db.PharmLocations.Where(p => p.LocationId == siteToSite.OriginatingLocationID).FirstOrDefault(); if (originatingLocation != null) { siteToSite.OriginatingLocationCode = originatingLocation.LocationCode; siteToSite.OriginatingLocationName = originatingLocation.Location; siteToSite.OriginatingLocationAddress1 = originatingLocation.Address1; siteToSite.OriginatingLocationAddress2 = originatingLocation.Address2; siteToSite.OriginatingLocationLocCity = originatingLocation.LocCity; siteToSite.OriginatingLocationLocState = originatingLocation.LocState; siteToSite.OriginatingLocationLocZip = originatingLocation.LocZip; siteToSite.OriginatingLocationPhoneMain = originatingLocation.PhoneMain; siteToSite.OriginatingLocationPhoneAlt = originatingLocation.PhoneAlt; siteToSite.OriginatingLocationFax = originatingLocation?.Fax; siteToSite.OriginatingLocationContact1Name = originatingLocation?.Contact1Name; siteToSite.OriginatingLocationContact2Name = originatingLocation?.Contact2Name; } }
SetDestinationLocation方法
private void SetDestinationLocation(SiteToSite siteToSite) { var destinationLocation = db.PharmLocations.Where(p => p.LocationId == siteToSite.DestinationLocationID).FirstOrDefault(); if (destinationLocation != null) { siteToSite.DestinationLocationCode = destinationLocation.LocationCode; siteToSite.DestinationLocationName = destinationLocation.Location; siteToSite.DestinationLocationAddress1 = destinationLocation.Address1; siteToSite.DestinationLocationAddress2 = destinationLocation.Address2; siteToSite.DestinationLocationLocCity = destinationLocation.LocCity; siteToSite.DestinationLocationLocState = destinationLocation.LocState; siteToSite.DestinationLocationLocZip = destinationLocation.LocZip; siteToSite.DestinationLocationPhoneMain = destinationLocation.PhoneMain; siteToSite.DestinationLocationPhoneAlt = destinationLocation.PhoneAlt; siteToSite.DestinationLocationFax = destinationLocation?.Fax; siteToSite.DestinationLocationContact1Name = destinationLocation?.Contact1Name; siteToSite.DestinationLocationContact2Name = destinationLocation?.Contact2Name; } }
GetSiteToSiteById方法
private void GetSiteToSiteById(SiteToSite siteToSite, int id) { var tmp = db.VwPart1SiteToSites.Where(p => p.InvOutItemPackageReceiptId == id).FirstOrDefault(); if (tmp != null) { if (siteToSite.CurrentVwPart1s == null) { siteToSite.CurrentVwPart1s = new List<VwPart1SiteToSite>(); } siteToSite.CurrentVwPart1s.Add(tmp); } }
解答
关于ViewModel构造函数调用的问题
你当前的代码逻辑里,ViewModel的构造函数不会在Post Action返回视图时被重新调用——因为你返回的是已经通过模型绑定创建好的SiteToSite实例(也就是Action参数里的对象),而非重新new一个新实例。
InventoryIn实例为空的原因
问题核心出在模型绑定机制:表单提交时,只有表单中存在的字段会被绑定到ViewModel属性上。如果InventoryIn的属性没有在视图中生成对应的输入控件(如<input>、<select>),或者控件命名不匹配,模型绑定器无法填充这些值,最终导致InventoryIn实例为空或属性值丢失。
解决建议
- 通过隐藏字段保留数据:若需要回传
InventoryIn的数据,在视图中为其每个需保留的属性添加隐藏字段(如@Html.HiddenFor(m => m.InventoryIn.PropertyName)),确保表单提交时这些值能被带回Controller。 - 重新加载数据:如果
InventoryIn的数据可从数据库或其他数据源获取,在Post Action中根据ViewModel的标识(如ID)重新查询并填充InventoryIn实例,类似你在RefreshSiteToSite中处理地址信息的逻辑。 - 检查控件命名匹配:确保视图中输入控件的名称与ViewModel属性名称完全一致(如
InventoryIn.PropertyName),模型绑定器依赖名称匹配完成赋值。
额外注意
视图中的两个<form>标签,需确保每个表单包含当前步骤回传所需的所有必要数据。尤其是从Step2返回Step1时,Step1依赖的所有字段要么在表单中存在,要么在Action中重新加载,否则ViewModel对应属性会丢失数据。
内容的提问来源于stack exchange,提问作者Rod
相关产品推荐
相关产品推荐

