我有一个控制器,它返回一个视图模型中传递的视图,该视图具有显示视图所需的属性(下拉选择项列表等)。
但是当我将它发布到服务器时,我有一个不同的模型类,它具有这些下拉列表的选定值。在我的HttpPost控制器操作中,我在进行任何处理之前检查(ModelState.IsValid),但是当它为false时,我返回View(模型) '背部。
但由于视图绑定到ViewModel,而我的Post动作正在接受实际模型,因此我收到错误' 传入字典的模型项的类型为' Model& #39;,但是当我提交表单时,此字典需要类型为' ViewModel' 的模型项,并且验证错误会显示在视图上。
我该如何解决这个问题?使用强类型视图,传入视图模型,但提交到其他模型时,最佳做法是什么?
代码:
public ActionResult Buy()
{
BuyVM buyVM = GetBuyVM();
return View(buyVM);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Buy(BuyModel model)
{
if (ModelState.IsValid)
{
// Do Procesing
return View("Success");
}
return View(model);
}
public class BuyVM
{
public SelectList PurchaseDateList { get; set; }
public SelectList BedroomsList { get; set; }
public SelectList StoriesList { get; set; }
[Required]
public string SquareFootage { get; set; }
[Required]
public string PreferredCityLocations { get; set; }
public string AdditionalInfo { get; set; }
}
public class BuyModel
{
public string PurchaseDateList { get; set; }
public string BedroomsList { get; set; }
public string StoriesList { get; set; }
public string SquareFootage { get; set; }
public string PreferredCityLocations { get; set; }
public string AdditionalInfo { get; set; }
}
private static BuyVM GetBuyVM()
{
BuyVM buyVM = new BuyVM();
buyVM.PurchaseDateList = new SelectList(new[] { "Immediately", "1 to 3 months", "4 to 6 months", "More than 6 months" });
buyVM.BedroomsList = new SelectList(new[] { "1", "2", "3", "4", "5+" });
buyVM.StoriesList = new SelectList(new[] { "1", "2", "Does not matter" });
return buyVM;
}
Buy.cshtml
@model Models.BuyVM
// html
@Html.DropDownListFor(m => m.PurchaseDateList, Model.PurchaseDateList, new { @class = "form-control" })
@Html.DropDownListFor(m => m.BedroomsList, Model.BedroomsList, new { @class = "form-control" })
所以当我返回View(模型)时,如果有验证错误(JQueryVal),在HTTPPost中,我试图显示验证错误,如果我将模型传递回视图。但我有这种类型不匹配。
答案 0 :(得分:3)
首先,您的数据模型的名称没有意义。名为BedroomsList
的属性建议Bedrooms
的集合,但属性为string
。首先命名您的属性来描述它们是什么,以便其他人可以理解您的代码。
public class BuyModel
{
public string PurchaseDate { get; set; }
public string Bedrooms { get; set; }
public string Stories { get; set; }
public string SquareFootage { get; set; }
public string PreferredCityLocations { get; set; }
public string AdditionalInfo { get; set; }
}
相应的视图模型需要包含这些属性以及SelectList
属性。
public class BuyVM
{
public string PurchaseDate { get; set; }
public string Bedrooms { get; set; }
public string Stories { get; set; }
[Required]
public string SquareFootage { get; set; }
[Required]
public string PreferredCityLocations { get; set; }
public string AdditionalInfo { get; set; }
public SelectList PurchaseDateList { get; set; }
public SelectList BedroomsList { get; set; }
public SelectList StoriesList { get; set; }
}
接下来删除GetBuyVM()
方法并将其替换为填充选择列表的控制器中的方法,以便在ModelState
无效且您需要返回视图时也可以调用该方法将POST方法更改为参数到您的视图模型(您的视图基于BuyVM
,因此您必须回发到BuyVM
,而不是BuyModel
)
public ActionResult Buy()
{
BuyVM model = new BuyVM(); // initalise an instance of the view model
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Buy(BuyVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
Initialize your data model and map the view model properties to it
BuyModel dataModel = new BuyModel()
{
PurchaseDate = model.PurchaseDate,
Bedrooms = model.Bedrooms,
....
};
// save the data model
return View("Success");
}
private ConfigureViewModel(BuyVM model)
{
model.PurchaseDateList = new SelectList(new[] { "Immediately", "1 to 3 months", "4 to 6 months", "More than 6 months" });
model.BedroomsList = new SelectList(new[] { "1", "2", "3", "4", "5+" });
model.StoriesList = new SelectList(new[] { "1", "2", "Does not matter" });
}
最后在视图中,绑定到您的媒体资源(PurchaseDate
,而不是PurchaseDateList
)
@Html.DropDownListFor(m => m.PurchaseDate, Model.PurchaseDateList)
@Html.DropDownListFor(m => m.Bedrooms, Model.BedroomsList)
答案 1 :(得分:0)
在回发后,如果视图模型有效,则将视图模型移动到实体模型。请注意,Post采用了一个视图模型,可以防止您暴露通常被认为不安全的实体模型。像AutoMapper这样的工具非常适用于此,但您可以手动完成:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Buy(BuyVM buyVM)
{
if (ModelState.IsValid)
{
var buyModel = new BuyModel {
PurchaseDateList = buyVM.PurchaseDateList,
BedroomsList = buyVM.BedroomsList,
...
};
// Do Procesing, Save Entity Model
}
// Otherwise, reset unbound fields on viewmodel
buyVM.List = GetList();
...
return View(buyVM);
}
MVC会自动传回错误信息。
答案 2 :(得分:-1)
在返回视图之前,您必须重新构建视图模型 - 这意味着,在返回视图之前,包含您的模型,重建所有下拉列表等。
您还可以考虑在Post动作中找到一种方法来使用viewmodel。