从这个问题来看,让控制器创建一个更准确地反映视图试图显示的模型的ViewModel似乎是有意义的,但我对一些约定很好奇。

基本上,我有以下几个问题:

我通常喜欢有一个类/文件。如果创建ViewModel只是为了将数据从控制器传递给视图,那么这对ViewModel有意义吗? 如果ViewModel属于它自己的文件,并且您正在使用目录/项目结构来保持内容分离,那么ViewModel文件属于哪里?在Controllers目录下?

现在基本上就是这样了。我可能会有更多的问题,但这已经困扰了我一个小时左右,我似乎可以在其他地方找到一致的指导。

编辑: 查看CodePlex上的示例NerdDinner应用程序,它看起来像视图模型是控制器的一部分,但它仍然让我不舒服,因为它们不在自己的文件中。


当前回答

下面是我的最佳实践代码片段:

    public class UserController : Controller
    {
        private readonly IUserService userService;
        private readonly IBuilder<User, UserCreateInput> createBuilder;
        private readonly IBuilder<User, UserEditInput> editBuilder;

        public UserController(IUserService userService, IBuilder<User, UserCreateInput> createBuilder, IBuilder<User, UserEditInput> editBuilder)
        {
            this.userService = userService;
            this.editBuilder = editBuilder;
            this.createBuilder = createBuilder;
        }

        public ActionResult Index(int? page)
        {
            return View(userService.GetPage(page ?? 1, 5));
        }

        public ActionResult Create()
        {
            return View(createBuilder.BuildInput(new User()));
        }

        [HttpPost]
        public ActionResult Create(UserCreateInput input)
        {
            if (input.Roles == null) ModelState.AddModelError("roles", "selectati macar un rol");

            if (!ModelState.IsValid)
                return View(createBuilder.RebuildInput(input));

            userService.Create(createBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }

        public ActionResult Edit(long id)
        {
            return View(editBuilder.BuildInput(userService.GetFull(id)));
        }

        [HttpPost]
        public ActionResult Edit(UserEditInput input)
        {           
            if (!ModelState.IsValid)
                return View(editBuilder.RebuildInput(input));

            userService.Save(editBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }
}

其他回答

There are no good place to keep your models in. You can keep them in separate assembly if the project is big and there are a lot of ViewModels (Data Transfer Objects). Also you can keep them in separate folder of the site project. For example, in Oxite they are placed in Oxite project which contains a lot of various classes too. Controllers in Oxite are moved to separate project and views are in separate project too. In CodeCampServer ViewModels are named *Form and they are placed in UI project in Models folder. In MvcPress project they are placed in Data project, which also contains all code to work with database and a bit more (but I didn't recommend this approach, it's just for a sample) So you can see there are many point of view. I usually keep my ViewModels (DTO objects) in the site project. But when I have more than 10 models I prefer to move them to separate assembly. Usually in this case I'm moving controllers to separate assembly too. Another question is how to easily map all data from model to your ViewModel. I suggest to have a look at AutoMapper library. I like it very much, it does all dirty work for me. And I also I suggest to look at SharpArchitecture project. It provides very good architecture for projects and it contains a lot of cool frameworks and guidances and great community.

我为每个视图创建了所谓的“ViewModel”。我把它们放在MVC Web项目中一个名为ViewModels的文件夹中。我根据它们所代表的控制器和动作(或视图)来命名它们。所以如果我需要传递数据到会员控制器上的注册视图,我创建了一个MembershipSignUpViewModel.cs类,并把它放在ViewModels文件夹中。

然后我添加必要的属性和方法,以促进数据从控制器传输到视图。我使用Automapper从我的ViewModel到域模型,如果需要的话再返回。

这也适用于包含其他viewmodel类型属性的复合viewmodel。例如,如果你在成员控制器的索引页上有5个小部件,并且你为每个分部视图创建了一个ViewModel——你如何将数据从index动作传递给分部?你在MembershipIndexViewModel中添加一个MyPartialViewModel类型的属性,当呈现部分时,你将在Model.MyPartialViewModel中传递。

这样做允许您调整部分ViewModel属性,而不必更改Index视图。它仍然只是传入模型。MyPartialViewModel所以当你所做的只是向partial ViewModel添加一个属性时,你就不太可能需要通过整个partial链来修复一些东西。

我还将添加命名空间“MyProject.Web”。ViewModels”到网络。配置,以便允许我在任何视图中引用它们,而无需在每个视图上添加显式的import语句。只是让它更干净一点。

我们将所有的viewmodel都放在Models文件夹中(所有的业务逻辑都在一个单独的ServiceLayer项目中)

控制器中的代码:

    [HttpGet]
        public ActionResult EntryEdit(int? entryId)
        {
            ViewData["BodyClass"] = "page-entryEdit";
            EntryEditViewModel viewMode = new EntryEditViewModel(entryId);
            return View(viewMode);
        }

    [HttpPost]
    public ActionResult EntryEdit(Entry entry)
    {
        ViewData["BodyClass"] = "page-entryEdit";            

        #region save

        if (ModelState.IsValid)
        {
            if (EntryManager.Update(entry) == 1)
            {
                return RedirectToAction("EntryEditSuccess", "Dictionary");
            }
            else
            {
                return RedirectToAction("EntryEditFailed", "Dictionary");
            }
        }
        else
        {
            EntryEditViewModel viewModel = new EntryEditViewModel(entry);
            return View(viewModel);
        }

        #endregion
    }

视图模型中的代码:

public class EntryEditViewModel
    {
        #region Private Variables for Properties

        private Entry _entry = new Entry();
        private StatusList _statusList = new StatusList();        

        #endregion

        #region Public Properties

        public Entry Entry
        {
            get { return _entry; }
            set { _entry = value; }
        }

        public StatusList StatusList
        {
            get { return _statusList; }
        }

        #endregion

        #region constructor(s)

        /// <summary>
        /// for Get action
        /// </summary>
        /// <param name="entryId"></param>
        public EntryEditViewModel(int? entryId)
        {
            this.Entry = EntryManager.GetDetail(entryId.Value);                 
        }

        /// <summary>
        /// for Post action
        /// </summary>
        /// <param name="entry"></param>
        public EntryEditViewModel(Entry entry)
        {
            this.Entry = entry;
        }

        #endregion       
    }

项目:

DevJet。Web (ASP。NET MVC web 项目) DevJet.Web.App.Dictionary (a 单独的类库项目) 在这个项目中,我做了一些文件夹,比如: 木豆, BLL, 薄 VM(视图模型文件夹)

按类别划分类(控制器、视图模型、过滤器等)是毫无意义的。

如果你想为你的网站(/)的Home部分写代码,然后创建一个名为Home的文件夹,并在那里放置HomeController, IndexViewModel, AboutViewModel等,以及Home操作使用的所有相关类。

如果你有共享类,比如ApplicationController,你可以把它放在项目的根目录。

为什么要分离相关的东西(HomeController, IndexViewModel),而把完全没有关系的东西放在一起(HomeController, AccountController) ?


我就这个话题写了一篇博客。