我使用IModelEnricher
结合 Automapper 和属性来定义列表类型和选择列表提供程序之间的关系。我使用特定的 ActionResult 返回实体等,然后将我的实体自动映射到 ViewModel 并丰富选择列表所需的数据(以及所需的任何其他数据)。此外,将选择列表数据作为 ViewModel 的一部分保持您的控制器、模型和视图职责清晰。
定义 ViewModel ernicher 意味着在使用 ViewModel 的任何地方,它都可以使用相同的丰富器来获取其属性。因此,您可以在多个位置返回 ViewModel,它只会填充正确的数据。
在我的情况下,这在控制器中看起来像这样:
public virtual ActionResult Edit(int id)
{
return AutoMappedEnrichedView<PersonEditModel>(_personRepository.Find(id));
}
[HttpPost]
public virtual ActionResult Edit(PersonEditModel person)
{
if (ModelState.IsValid){
//This is simplified (probably don't use Automapper to go VM-->Entity)
var insertPerson = Mapper.Map<PersonEditModel , Person>(person);
_personRepository.InsertOrUpdate(insertPerson);
_requirementRepository.Save();
return RedirectToAction(Actions.Index());
}
return EnrichedView(person);
}
这种 ViewModel:
public class PersonEditModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public int FavouriteTeam { get; set; }
public IEnumerable<SelectListItem> Teams {get;set;}
}
有了这种浓缩器:
public class PersonEditModelEnricher :
IModelEnricher<PersonEditModel>
{
private readonly ISelectListService _selectListService;
public PersonEditModelEnricher(ISelectListService selectListService)
{
_selectListService = selectListService;
}
public PersonEditModelEnrich(PersonEditModel model)
{
model.Teams = new SelectList(_selectListService.AllTeams(), "Value", "Text")
return model;
}
}
另一种选择是使用定义数据如何定位以填充选择列表的属性来装饰 ViewModel。喜欢:
public class PersonEditModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public int FavouriteTeam { get; set; }
[LoadSelectListData("Teams")]
public IEnumerable<SelectListItem> Teams {get;set;}
}
现在您可以在您的选择服务中使用如下属性装饰一个适当的方法:
[ProvideSelectData("Teams")]
public IEnumerable Teams()
{
return _teamRepository.All.ToSelectList(a => a.Name, a => a.TeamId);
}
然后对于没有复杂浓缩的简单模型,只需通用浓缩过程就可以处理它。如果你想做更复杂的事情,你可以定义一个浓缩器,如果它存在,它将被使用。
其他选项可能是配置方法的约定,其中 Enricher 会查看属性名称和类型,例如IEnumerable<SelectListItem> PossibleFirstDivisionTeams
{get;set;} 然后如果它与一个选择列表提供程序名称存在于一个类中,该类表示实现了一个标记接口,则将其匹配ISelectListProvider
。我们采用了基于属性的方法,刚刚创建了表示各种列表的 Enums Eg SelectList.AllFirstDivisionTeams
。也可以尝试 ViewModel 上只有一个用于选择列表的属性集合的接口。我真的不喜欢我的 ViewModel 上的接口,所以我们从来没有这样做过
这完全取决于您的应用程序的规模以及跨多个模型需要相同类型的选择列表数据的频率。您需要澄清的任何具体问题或要点让我知道
看到这个问题。还有这篇博文和这个。Automapper论坛上的这个问题