具有SelectList(s)最佳实践的ASP.NET MVC ViewModel

Bob*_*erg 14 asp.net-mvc selectlist

我注意到在NerdDinner应用程序中,如果ModelState对于晚餐无效,它只返回模型的视图:

        if (ModelState.IsValid) {
            ...
            return RedirectToAction("Details", new { id=dinner.DinnerID });
        }

        return View(dinner);
Run Code Online (Sandbox Code Playgroud)

但是,在我的应用程序中,模型(在这种情况下的视图模型)包含多个SelectLists.此时未实例化这些列表,因为此视图模型刚刚从表单提交中填充.在将此SelectLists发送回用户之前,重新填充此SelectLists的建议方法是什么?

这就是我希望我的控制器做的事情:

public ActionResult Save(MyModel model)
{
    if (ModelState.IsValid)
    {
        businessClass.Save(model);
        return RedirectToAction("Index", "Home");
    }

    // This won't work because model has uninstantiated SelectLists
    return View("MyView", model);
}
Run Code Online (Sandbox Code Playgroud)

我不想对模型发送到我的业务逻辑,如果ModelState中是无效的,但它似乎并没有什么意义放的SelectList人口代码在我的控制器.我应该在我的业务逻辑中创建一个公共方法,仅仅是为了在我的视图模型上做这种事情吗?

Joh*_*ter 15

就个人而言,我喜欢保持简单: -

[HttpGet]
public Edit(int id) {
     EditForm form = new EditForm();
     // Populate from the db or whatever...
     PopulateEditPageSelectLists(form);
     return View(form);
}

[HttpPost]
public Edit(EditForm form) {
     if (ModelState.IsValid) {
         // Do stuff and redirect...
     }
     PopulateEditPageSelectLists(form);
     return View(form);
}

public void PopulateEditPageSelectLists(form) {
     // Get lookup data from the db or whatever.
}
Run Code Online (Sandbox Code Playgroud)

如果填充选择列表的逻辑是疯狂的,那么移动到一个单独的类或任何它可能是值得的,但作为第一步,这是最好的起点.


rou*_*uen 5

你不想说你想要多少可重用性.但就个人而言,我喜欢"清晰"(不要侵入控制器)并且尽可能地重新使用"MVC"意味着 - 过滤器.

看这个 :

public class SupplyLanguagesAttribute : System.Web.Mvc.ActionFilterAttribute
{
    public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
    {
        filterContext.Controller.ViewData["languagesList"] =
            someService.LoadLanguagesAsDictionary();

        base.OnActionExecuting(filterContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你只需将它用于"可能"需要语言的每种操作方法:

[SupplyLanguages]
public ActionResult DoSomething()
{
...
}
Run Code Online (Sandbox Code Playgroud)

然后在视图中,您可以直接从ViewData使用DropDownList的数据,或者您甚至可以使用自定义可重用的DropDown"包装"它(并避免视图中的"魔术字符串"):

public static MvcHtmlString LanguageDropDown(this HtmlHelper html, string name, object selectValue, bool defaultOption = false)
    {
        var languages = html.ViewData["languagesList"] as IDictionary<string,string>;

        if (languages == null || languages.Count() == 0)
            throw new ArgumentNullException("LanguageDropDown cannot operate without list of languages loaded in ViewData. Use SupplyLanguages filter.");

        var list = new SelectList(languages, "Key", "Value", selectValue);

        return SelectExtensions.DropDownList(html, name, list);
    }
Run Code Online (Sandbox Code Playgroud)