我有各种viewmodel,它们具有必须填充的属性。例如,想象一个充满国家的数据库表。我有一个创建用户页面,viewmodel上的一个属性是List<string> Countries
。
最初我在无参数构造函数中填充了这个,即
public CreateUserViewModel()
{
this.Countries = new CountryManager().GetCountries();
}
但我读到这是一个不好的做法,我应该把它们传入。
public CreateUserViewModel(IEnumerable<string> countries)
{
this.Countries = countries;
}
但是在我的帖子中,这些数据丢失,如果验证失败,它会重定向到视图,但那时countries属性为null。
我想知道我应该如何重新填充这个值。手动将一些代码放入控制器post方法似乎很糟糕,例如。
[HttpPost]
public ActionResult CreateUser(CreateUserViewModel vm)
{
if (Model.IsValid)
{
new UserManager().CreateUser(vm);
}
else
{
vm.Countries = new CountryManager().GetCountries();
return View(vm);
}
}
我正在努力谷歌这可能是一个非常常见的问题。有什么想法吗?
答案 0 :(得分:3)
避免无参数构造函数背后的基本原理是控制反转。在这种情况下,逻辑是Countries
是一个依赖项,并且通过外化该依赖项(以便它被注入到类中),您可以使您的类更不易碎并且更容易扩展。
然而,我认为实际上并不适用于你的场景,因为Countries
并不是你班级的依赖,而是你的视图。视图模型用于提供视图,并且在某种程度上是封闭的,不可扩展的无论如何。换句话说,请遵循服务,存储库,实用程序类等内容的控制反转,但对于视图模型,它并不是真正必要或重要的。
无论如何,这是我如何处理这类事情:
public class FooViewModel
{
...
// Countries is not initialize by a constructor
public IEnumerable<SelectListItem> Countries { get; set; }
}
然后在你的控制器中:
public class FooController : Controller
{
internal void PopulateCountryChoices(FooViewModel model)
{
// fetch countries
model.Countries = countries.Select(m => new SelectListItem
{
Text = m.Name,
Value = m.Id.ToString()
});
}
public ActionResult Bar()
{
var model = new FooViewModel();
PopulateCountryChoices(model);
return View(model);
}
[HttpPost]
public ActionResult Bar(FooViewModel model)
{
if (ModelState.IsValid)
{
// save and redirect
}
PopulateCountryChoices(model);
return View(model);
}
}
答案 1 :(得分:1)
我们可以在视图中填充Dropdownlist值,而不是在模型中填充此静态数据 -
@Html.DropDownListFor(model => model.State,
new SelectList(Utils.GetCountries()),
"value",
"text",
2)
其中Utils是一个返回所有国家的助手类。
这种填充所有静态数据的方式(我的意思是Dropdownlist或Listbox等的所有选项)都将由View接管,这使得模型可以免于保存这些数据。