Asp.Net MVC之ViewData字典与ViewModel模式
2015-06-02 09:22
232 查看
从Controller传递数据到View视图模板MVC模式一个典型的特征是严格的功能隔离。Model模型、Controller控制器和View视图各自定义了作用和职责,且相互之间以定义好的方式进行沟通。这有助于提升测试性和代码重用。当Controller决定呈现HTML响应给客户端是,它负责显式传递给View模板所有需要的数据。View模板从不执行任何数据查询或应用程序逻辑 – 仅仅负责呈现Model或Controller传递过来的数据。当需要从Controller传递不止一个Model对象时,就要用到ViewData字典或ViewModel模式。例如,当我们需要Controller在View呈现Dinner对象和支持的Countries列表的时候,采用如下两种方式来实现。使用ViewData 字典Controller基类公开了一个ViewData 字典属性,用来从Controllers传递额外的数据给Views视图。
Controller中代码
[Authorize]
public ActionResult Edit(int id)
{
Dinner dinner = dinnerRepository.GetDinner(id);
ViewData["Countries"] = new SelectList(PhoneValidator.Countries, dinner.Country);
return View(dinner);
}
上面代码中SelectList构造函数的第一个参数显示国家列表,第二个参数指定当前选中的国家。
View中代码
<%= Html.DropDownList("Country", ViewData["Countries"] as SelectList)%>
上面代码中第一个参数表示输出的HTML表单元素名称,第二个参数是通过ViewData传递的模型类。
使用ViewModel模式:
ViewData的优点:非常快,容易实现
ViewData的缺点:输入错误会导致错误;不能在编译期发现错误原因;在View视图模板中使用强类型时,ViewData要用as来转换。
ViewModel模式:
1.针对特定的View视图创建强类型的类
2.公开View模板需要的动态参数值或内容
3.Controller类填充和传递这些类给View模板去用
4.优点:类型安全、编译期检查和编辑器的智能提示
示例代码:
public class DinnerFormViewModel
{
public Dinner Dinner {get; private set;}
public SelectList Countries{get; private set;}
public DinnerFormViewModel(Dinner dinner)
{
Dinner = dinner;
Countries = new SelectList(PhoneValidator.Countries,dinner.Country);
} }
在Controller类中
[Authorize]
public ActionResult Edit(int id)
{
Dinner dinner = dinnerRepository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
}
在View视图模板中
头部Inherits = "System.Web.Mvc.ViewPage<NerdDinner.Models.Dinner>"改为
Inherits = "System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerFormViewModel>"
绑定列表即为<% = Html.DropDownList("Country".Model.Countries) %>下面我们需要更新视图中的代码。对于表单中的HTML元素的名称不需要更新,仍旧保持为Title、Country等等,我们需要更新HTML辅助方法,使用DinnerFormViewModel类来获取属性值。[align=left]<p>[/align][align=left]<label for="Title">Dinner Title:</label>[/align][align=left]<%= Html.TextBox("Title", Model.Dinner.Title) %>[/align][align=left]<%= Html.ValidationMessage("Title", "*") %>[/align][align=left]</p>[/align][align=left]<p>[/align][align=left]<label for="Country">Country:</label>[/align][align=left]<%= Html.DropDownList("Country", Model.Countries) %>[/align][align=left]<%= Html.ValidationMessage("Country", "*") %>[/align][align=left]</p>[/align]同样地,我们也需要更新Edit Post方法,在产生错误时,使用DinnerFormViewModel类传递给视图模板:[align=left]//[/align][align=left]// POST: /Dinners/Edit/5[/align][align=left][[/align][align=left]AcceptVerbs(HttpVerbs.Post)][/align][align=left]public ActionResult Edit(int id, FormCollection collection) {[/align][align=left]Dinner dinner = dinnerRepository.GetDinner(id);[/align][align=left]try {[/align][align=left]UpdateModel(dinner);[/align][align=left]dinnerRepository.Save();[/align][align=left]return RedirectToAction("Details", new { id=dinner.DinnerID });[/align][align=left]}[/align][align=left]catch {[/align][align=left]ModelState.AddModelErrors(dinner.GetRuleViolations());[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}[/align][align=left]}[/align]我们也更新Create() Action方法,重用相同的DinnerFormViewModel类,在View中实现Country下拉列表框。下面是HTTP-GET的实现代码:[align=left]//[/align][align=left]// GET: /Dinners/Create[/align][align=left]public ActionResult Create() {[/align][align=left]Dinner dinner = new Dinner() {[/align][align=left]EventDate = DateTime.Now.AddDays(7)[/align][align=left]};[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}[/align]下面是HTTP-POST Create方法的实现代码:[align=left]//[/align][align=left]// POST: /Dinners/Create[/align][align=left][AcceptVerbs(HttpVerbs.Post)][/align][align=left]public ActionResult Create(Dinner dinner) {[/align][align=left]if (ModelState.IsValid) {[/align][align=left]try {[/align][align=left]dinner.HostedBy = "SomeUser";[/align][align=left]dinnerRepository.Add(dinner);[/align][align=left]dinnerRepository.Save();[/align][align=left]return RedirectToAction("Details", new { id=dinner.DinnerID });[/align][align=left]}[/align][align=left]catch {[/align][align=left]ModelState.AddModelErrors(dinner.GetRuleViolations());[/align][align=left]}[/align][align=left]}[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}定制ViewModel类(Custom-shaped ViewModel Classes)[/align]在上面的实现方案中,DinnerFormViewModel类直接公开了2个公有属性:Dinner 模型对象和SelectList模型属性。这一方法适合于View模板中HTML用户界面元素和业务Model对象比较接近的场景。如果不符合这一情况,可以考虑创建定制的ViewModel类,根据视图的使用情况创建优化的对象模型 – 该对象模型可能完全不同于底层的业务模型对象(Domain Model Object)。例如,该ViewModel类有可能公开不同的属性或者从多个Model对象中汇总的属性。定制的ViewModel类不仅可用来从Controller传递数据到View去呈现,而且可用来处理从表单提交回来给Controller的action方法的数据。针对后一种情况,你可以让Action方法根据表单提交回来的数据更新ViewModel对象,接着使用ViewModel实例来映射或者获取时间的业务模型对象(Domain Model Object)。定制ViewModel类提供了很好的灵活性,在任何时候,你发现View模板中的呈现代码或Action方法中表单提交代码越来越开始复杂时,你可以考虑使用定制的ViewModel了。通常,这意味着业务模型对象和View视图中的用户界面元素不一致,一个中介的定制ViewModel类就可以发挥作用了。
Controller中代码
[Authorize]
public ActionResult Edit(int id)
{
Dinner dinner = dinnerRepository.GetDinner(id);
ViewData["Countries"] = new SelectList(PhoneValidator.Countries, dinner.Country);
return View(dinner);
}
上面代码中SelectList构造函数的第一个参数显示国家列表,第二个参数指定当前选中的国家。
View中代码
<%= Html.DropDownList("Country", ViewData["Countries"] as SelectList)%>
上面代码中第一个参数表示输出的HTML表单元素名称,第二个参数是通过ViewData传递的模型类。
使用ViewModel模式:
ViewData的优点:非常快,容易实现
ViewData的缺点:输入错误会导致错误;不能在编译期发现错误原因;在View视图模板中使用强类型时,ViewData要用as来转换。
ViewModel模式:
1.针对特定的View视图创建强类型的类
2.公开View模板需要的动态参数值或内容
3.Controller类填充和传递这些类给View模板去用
4.优点:类型安全、编译期检查和编辑器的智能提示
示例代码:
public class DinnerFormViewModel
{
public Dinner Dinner {get; private set;}
public SelectList Countries{get; private set;}
public DinnerFormViewModel(Dinner dinner)
{
Dinner = dinner;
Countries = new SelectList(PhoneValidator.Countries,dinner.Country);
} }
在Controller类中
[Authorize]
public ActionResult Edit(int id)
{
Dinner dinner = dinnerRepository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
}
在View视图模板中
头部Inherits = "System.Web.Mvc.ViewPage<NerdDinner.Models.Dinner>"改为
Inherits = "System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerFormViewModel>"
绑定列表即为<% = Html.DropDownList("Country".Model.Countries) %>下面我们需要更新视图中的代码。对于表单中的HTML元素的名称不需要更新,仍旧保持为Title、Country等等,我们需要更新HTML辅助方法,使用DinnerFormViewModel类来获取属性值。[align=left]<p>[/align][align=left]<label for="Title">Dinner Title:</label>[/align][align=left]<%= Html.TextBox("Title", Model.Dinner.Title) %>[/align][align=left]<%= Html.ValidationMessage("Title", "*") %>[/align][align=left]</p>[/align][align=left]<p>[/align][align=left]<label for="Country">Country:</label>[/align][align=left]<%= Html.DropDownList("Country", Model.Countries) %>[/align][align=left]<%= Html.ValidationMessage("Country", "*") %>[/align][align=left]</p>[/align]同样地,我们也需要更新Edit Post方法,在产生错误时,使用DinnerFormViewModel类传递给视图模板:[align=left]//[/align][align=left]// POST: /Dinners/Edit/5[/align][align=left][[/align][align=left]AcceptVerbs(HttpVerbs.Post)][/align][align=left]public ActionResult Edit(int id, FormCollection collection) {[/align][align=left]Dinner dinner = dinnerRepository.GetDinner(id);[/align][align=left]try {[/align][align=left]UpdateModel(dinner);[/align][align=left]dinnerRepository.Save();[/align][align=left]return RedirectToAction("Details", new { id=dinner.DinnerID });[/align][align=left]}[/align][align=left]catch {[/align][align=left]ModelState.AddModelErrors(dinner.GetRuleViolations());[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}[/align][align=left]}[/align]我们也更新Create() Action方法,重用相同的DinnerFormViewModel类,在View中实现Country下拉列表框。下面是HTTP-GET的实现代码:[align=left]//[/align][align=left]// GET: /Dinners/Create[/align][align=left]public ActionResult Create() {[/align][align=left]Dinner dinner = new Dinner() {[/align][align=left]EventDate = DateTime.Now.AddDays(7)[/align][align=left]};[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}[/align]下面是HTTP-POST Create方法的实现代码:[align=left]//[/align][align=left]// POST: /Dinners/Create[/align][align=left][AcceptVerbs(HttpVerbs.Post)][/align][align=left]public ActionResult Create(Dinner dinner) {[/align][align=left]if (ModelState.IsValid) {[/align][align=left]try {[/align][align=left]dinner.HostedBy = "SomeUser";[/align][align=left]dinnerRepository.Add(dinner);[/align][align=left]dinnerRepository.Save();[/align][align=left]return RedirectToAction("Details", new { id=dinner.DinnerID });[/align][align=left]}[/align][align=left]catch {[/align][align=left]ModelState.AddModelErrors(dinner.GetRuleViolations());[/align][align=left]}[/align][align=left]}[/align][align=left]return View(new DinnerFormViewModel(dinner));[/align][align=left]}定制ViewModel类(Custom-shaped ViewModel Classes)[/align]在上面的实现方案中,DinnerFormViewModel类直接公开了2个公有属性:Dinner 模型对象和SelectList模型属性。这一方法适合于View模板中HTML用户界面元素和业务Model对象比较接近的场景。如果不符合这一情况,可以考虑创建定制的ViewModel类,根据视图的使用情况创建优化的对象模型 – 该对象模型可能完全不同于底层的业务模型对象(Domain Model Object)。例如,该ViewModel类有可能公开不同的属性或者从多个Model对象中汇总的属性。定制的ViewModel类不仅可用来从Controller传递数据到View去呈现,而且可用来处理从表单提交回来给Controller的action方法的数据。针对后一种情况,你可以让Action方法根据表单提交回来的数据更新ViewModel对象,接着使用ViewModel实例来映射或者获取时间的业务模型对象(Domain Model Object)。定制ViewModel类提供了很好的灵活性,在任何时候,你发现View模板中的呈现代码或Action方法中表单提交代码越来越开始复杂时,你可以考虑使用定制的ViewModel了。通常,这意味着业务模型对象和View视图中的用户界面元素不一致,一个中介的定制ViewModel类就可以发挥作用了。
相关文章推荐
- ASP.NET MVC中ActionResult返回值
- ASP.NET MVC Razor视图引擎攻略
- 在ASP.NET MVC中实现大文件异步上传
- 安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x80070643), "安装时发生严重错误 " (Ela)
- ASP.NET MVC部署到IIS
- 关于asp.net中页面事件加载的先后顺序(转)
- ASP.NET MVC中Controller与View之间的数据传递总结
- 基于ASP.NET4开发的MVC2网站在WINDOWS2003服务器上的布署
- ASP.NET MVC网站路由配置
- ASP.NET MVC HtmlHelper
- Asp.net MVC2学习笔记8-数据验证(前后台统一验证)
- ASP.NET网站集成Discuz!NT 3.1论坛详细教程(同步注册和登录)
- asp.net页面事件执行顺序
- 关于HTML界面改为aspx页面时CSS失效的问题
- Asp.Net Forms验证(自定义、角色提供程序、单点登录)
- Asp.Net Forms验证(自定义、角色提供程序)
- 分析在ASP.NET中运用PlaceHolder控件
- asp.net重写URL
- .NET开发中的事务处理大比拼 之 ASP.NET页面级别的事务
- 解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑