MVC - 具有多个选择列表的控制器

时间:2012-02-03 21:59:25

标签: c# asp.net-mvc

当他们拥有依赖于大量选择列表的模型时,有没有什么好方法可以让我的控制器更简单?我尽量保持我的大多数控制器操作尽可能简单(希望不超过10行),但在需要大量下拉菜单的页面上,我的操作通常会超出此范围:

public class Model
{
    public IEnumerable<SelectListItem> AllLocations { get; set; }
    public IEnumerable<SelectListItem> TopLocations { get; set; }
    public IEnumerable<SelectListItem> AllTemplates { get; set; }
    public IEnumerable<SelectListItem> TopTemplates { get; set; }
    // ...
}

[HttpGet]
public ActionResult Index(int id)
{
    var domain = Repository.Get(id);
    var model = Mapper.Map<Domain, ViewModel>(item);

    // any way to abstract this type of code?
    model.AllLocations = new SelectList(repository.GetAllLocations(), "Value", "Text");
    model.TopLocations = new SelectList(repository.GetTopLocations(), "Value", "Text");
    model.AllTemplates = new SelectList(repository.GetAllTemplates(), "Value", "Text");
    model.TopTemplates = new SelectList(repository.GetTopTemplates(), "Value", "Text");
    // etc. etc.

    return View(model);
}

[HttpPost]
public ActionResult Index(ViewModel model)
{
    // any way to abstract this type of code?
    model.AllLocations = new SelectList(repository.GetAllLocations(), "Value", "Text");
    model.TopLocations = new SelectList(repository.GetTopLocations(), "Value", "Text");
    model.AllTemplates = new SelectList(repository.GetAllTemplates(), "Value", "Text");
    model.TopTemplates = new SelectList(repository.GetTopTemplates(), "Value", "Text");
    // etc. etc.

    return View(model);
}

3 个答案:

答案 0 :(得分:3)

正如你所说保持控制器动作小很多。正如吉米·博加德所说put your controllers on a diet

我使用IModelEnricher与Automapper结合使用。我使用特定的ActionResult返回一个实体等,然后将我的实体自动化为ViewModel,并丰富选择列表所需的数据(以及所需的任何其他数据)。这种方法让您的代码DRY和控制器像超级模型一样瘦:-)!同时将选择列表数据保留为ViewModel的一部分可以使您的控制器,模型和查看职责保持清晰。

定义ViewModel ernicher意味着在使用ViewModel的任何地方,它都可以使用相同的richher来获取其属性。因此,您可以在多个位置返回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= new List<SelectListItem>();
}

有了这种Enricher:

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= new List<SelectListItem>();
    }

现在,您可以在选择服务中使用以下属性修饰适当的方法:

   [ProvideSelectData("Teams")]
   public IEnumerable Teams()
   {
        return _teamRepository.All.ToSelectList(a => a.Name, a => a.TeamId);
   }

然后对于没有复杂浓缩的简单模型,只需通用浓缩过程就可以处理它。如果你想做更复杂的事情,你可以定义一个更丰富的,如果它存在就会被使用。

question。还有blog postthis。这也是Automapper论坛上的question

答案 1 :(得分:2)

您可以设置一个帮助程序类,将每个选择列表放在一个静态方法中。然后,在视图中,您可以通过htmlhelper获取每个选择列表。控制器将清除。同时,其他视图也可以使用这些选择列表。

例如:

public class SelectHelper
{
     public static List<SelectListItem> AllLocations()
     {
         //TODO repository.GetAllLocations()
     }
     public static List<SelectListItem> TopLocations()
     {
         //TODO repository.GetTopLocations()
     }
     ...
}

查看代码:        @ Html.DropDownList(“selectname”,SelectHelper.AllLocations())

答案 2 :(得分:1)

当然,只需将它重构为一个方法,就像这样:

public class Model
{
    public IEnumerable<SelectListItem> AllLocations { get; set; }
    public IEnumerable<SelectListItem> TopLocations { get; set; }
    public IEnumerable<SelectListItem> AllTemplates { get; set; }
    public IEnumerable<SelectListItem> TopTemplates { get; set; }
    // ...
}

[HttpGet]
public ActionResult Index(int id)
{
    var domain = Repository.Get(id);
    var model = Mapper.Map<Domain, ViewModel>(item);
    InitializeSelectLists(model);

    return View(model);
}

[HttpPost]
public ActionResult Index(ViewModel model)
{
    InitializeSelectLists(model);
    View(model);
}


private void InitializeSelectLists(Model model)
{
    model.AllLocations = new SelectList(repository.GetAllLocations(), "Value", "Text");
    model.TopLocations = new SelectList(repository.GetTopLocations(), "Value", "Text");
    model.AllTemplates = new SelectList(repository.GetAllTemplates(), "Value", "Text");
    model.TopTemplates = new SelectList(repository.GetTopTemplates(), "Value", "Text");
    // etc. etc.
}

或者,如果您愿意,您甚至可以在模型的构造函数或外观服务中执行此操作。