从这个问题来看,让控制器创建一个更准确地反映视图试图显示的模型的ViewModel似乎是有意义的,但我对一些约定很好奇。
基本上,我有以下几个问题:
我通常喜欢有一个类/文件。如果创建ViewModel只是为了将数据从控制器传递给视图,那么这对ViewModel有意义吗?
如果ViewModel属于它自己的文件,并且您正在使用目录/项目结构来保持内容分离,那么ViewModel文件属于哪里?在Controllers目录下?
现在基本上就是这样了。我可能会有更多的问题,但这已经困扰了我一个小时左右,我似乎可以在其他地方找到一致的指导。
编辑:
查看CodePlex上的示例NerdDinner应用程序,它看起来像视图模型是控制器的一部分,但它仍然让我不舒服,因为它们不在自己的文件中。
我为每个视图创建了所谓的“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语句。只是让它更干净一点。
控制器中的代码:
[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(视图模型文件夹)
创建一个视图模型基类,它具有通常需要的属性,如操作结果和上下文数据,您还可以放置当前用户数据和角色
class ViewModelBase
{
public bool HasError {get;set;}
public string ErrorMessage {get;set;}
public List<string> UserRoles{get;set;}
}
在基控制器类中,有一个类似PopulateViewModelBase()的方法,该方法将填充上下文数据和用户角色。
HasError和ErrorMessage,如果从service/db中提取数据时出现异常,请设置这些属性。在视图上绑定这些属性以显示错误。
用户角色可用于根据角色在视图中显示隐藏部分。
要在不同的get操作中填充视图模型,可以通过具有具有抽象方法FillModel的基本控制器使之一致
class BaseController :BaseController
{
public PopulateViewModelBase(ViewModelBase model)
{
//fill up common data.
}
abstract ViewModelBase FillModel();
}
在控制器
class MyController :Controller
{
public ActionResult Index()
{
return View(FillModel());
}
ViewModelBase FillModel()
{
ViewModelBase model=;
string currentAction = HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString();
try
{
switch(currentAction)
{
case "Index":
model= GetCustomerData();
break;
// fill model logic for other actions
}
}
catch(Exception ex)
{
model.HasError=true;
model.ErrorMessage=ex.Message;
}
//fill common properties
base.PopulateViewModelBase(model);
return model;
}
}