[索引页]
[×××]
返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性
做者:
webabcd
介绍
asp.net mvc 之 asp.net mvc 2.0 新特性:如经过 DataAnnotations 实现数据验证及客户端验证,MVC 与 Dynamic Data 的结合,对异步 Controller 的支持,对 Area 的支持,新增的一些帮助方法等
示例
一、新特性总结
Index.aspx
<%@ Page Language=
"C#" MasterPageFile=
"~/Views/Shared/Site.Master"
Inherits=
"System.Web.Mvc.ViewPage" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"TitleContent" runat=
"server">
Home Page
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"MainContent" runat=
"server">
<h2><%: ViewData[
"Message"] %></h2>
<p>
<a href=
"Category" target=
"_blank">Demo</a>
</p>
<p>
一、<a href=
"Category/Create" target=
"_blank">经过 DataAnnotations 实现数据验证;对客户端验证的支持</a>
</p>
<p>
二、<a href=
"AsynchronousController" target=
"_blank">对异步 Controller 的支持</a>
</p>
<p>
三、MVC 与 Dynamic Data 的结合
<br />
<a href=
"Category/Edit/21" target=
"_blank">实现 Model 级别的 Dynamic Data</a>
<br />
<a href=
"Category/Edit2/21" target=
"_blank">实现 Property 级别的 Dynamic Data</a>
<br />
新增了对模板的支持(模板源自 Dynamic Data)
</p>
<p>
ActionResult View() ActionResult View(int id, [DefaultValue(1)]int page) { }
</p>
<p>
五、关于路由的新特性,参看:http://webabcd.blog.51cto.com/1787395/341124
</p>
<p>
六、Html.Hidden() 加强 - 其能够用于保存二进制(Binary 类型或 byte[] 类型)数据
<br />
好比:
<br />
<%= Html.Hidden(
"Photo", Model.Photo) %>
<br />
生成的 html 为:
<br />
<input type=
"hidden" name=
"Photo" value=
"QVNQLk5FVCBNVkMgaXMgZnVuIQ................................." />
</p>
<p>
七、在 VS 2010 中增长了 asp.net mvc 相关的代码片断
<br />
组合键 ctrl+k ctrl+b 调出代码片断管理器后查看
</p>
<p>
八、新增了一个名为 RequireHttpsAttribute 的 Action Filter - 其做用就是用于只容许 HTTPS 请求。默认状况下,若是是 HTTP 请求,则会自动跳转到 HTTPS 请求
</p>
<p>
九、只有 HTTP POST 请求才能返回 JsonResult
</p>
<p>
十、新增了 HttpPostAttribute HttpPutAttribute HttpGetAttribute HttpDeleteAttribute ,之前是相似这样写的 AcceptVerbs(HttpVerbs.Post)
</p>
<p>
十一、UrlParameter.
Optional - 若是从url路由中没法获取某个参数的值,则从url参数中获取该参数的值。示例以下
<br />
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller =
"Home", action =
"Index", id = UrlParameter.
Optional }
);
<br />
<a href=
"Category/?pageIndex=0" target=
"_blank">使用 UrlParameter.
Optional 的一个演示</a>
</p>
<p>
十二、对 Area 的支持 - 容许在一个应用程序内存在多套 MVC,在项目中单击右键 -> Add -> Area...(详见示例程序中的 Areas 目录)
</p>
<p>
1三、新增的一些帮助方法
<br />
Html.EditorFor(), Html.DisplayFor(), Html.DisplayTextFor(), Html.ValidationMessageFor(), Html.TextBoxFor(), Html.TextAreaFor(), Html.DropDownListFor(), Html.CheckboxFor(), Html.RadioButtonFor(), Html.ListBoxFor(), Html.PasswordFor(), Html.HiddenFor(), Html.LabelFor()
<br />
它们主要用于实现 Scaffold,以及为 Property 或 Model 指定显示模板或编辑模板
</p>
</asp:Content>
二、异步 Controller 的 Demo
Areas/AsynchronousController/Controllers/HomeController.cs
/*
* ASP.NET MVC 2.0 - 异步 Controller
* 一、须要继承基类 AsyncController
* 二、在 Async 为后缀的方法中写发起异步操做的逻辑;在 Completed 为后缀的方法中写异步操做完成后的逻辑;此两个方法的前缀就是这个异步 Controller 的 Action
* 三、AsyncManager.OutstandingOperations.Increment() - 递增当前异步操做的计数器;AsyncManager.OutstandingOperations.Decrement(); - 递减当前异步操做的计数器。当异步操做的计数器为 0 时,则调用以 Completed 为后缀的方法
* 四、AsyncManager.Parameters[key] - 传递指定参数到以 Completed 为后缀的方法中
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Net;
using System.Xml;
using System.ServiceModel.Syndication;
namespace MVC20.Areas.AsynchronousController.Controllers
{
[HandleError]
public
class HomeController : AsyncController
{
// IndexAsync() 以及 IndexCompleted() 是一对,其 Action 为 Index
// 开始一个异步操做
void IndexAsync() void IndexAsync()
{
// 递增计数器
AsyncManager.OutstandingOperations.Increment();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
"http://www.cnblogs.com/webabcd/rss");
request.BeginGetResponse(
new AsyncCallback(OnGetRssFeedAsyncCompleted), request);
}
// 完成异步操做后
ActionResult IndexCompleted() ActionResult IndexCompleted(IEnumerable<SyndicationItem> items)
{
ViewData[
"Message"] =
"Welcome to ASP.NET MVC!";
ViewData[
"SyndicationItems"] = items;
return View();
}
void OnGetRssFeedAsyncCompleted() void OnGetRssFeedAsyncCompleted(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
using (XmlReader reader = XmlReader.Create(response.GetResponseStream()))
{
SyndicationFeed feed = SyndicationFeed.Load(reader);
// 传递指定参数到 IndexCompleted() 方法中
AsyncManager.Parameters[
"items"] = feed.Items;
// 递减计数器,当计数器为 0 时,则调用 IndexCompleted()
AsyncManager.OutstandingOperations.Decrement();
}
}
}
}
Areas/AsynchronousController/Views/Home/Index.aspx
<%@ Page Language=
"C#"
Inherits=
"System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Import Namespace=
"System.ServiceModel.Syndication" %>
<!DOCTYPE html
PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=
"http://www.w3.org/1999/xhtml">
<head runat=
"server">
<title>Index</title>
</head>
<body>
<div>
<h2>
<%: ViewData[
"Message"] %></h2>
<div>
<!--
调用异步 Controller 的 Demo
注意:
Inherits=
"System.Web.Mvc.ViewPage<dynamic>",这里用了 dynamic 类型
-->
<% foreach (SyndicationItem item
in (IEnumerable<SyndicationItem>)ViewData[
"SyndicationItems"])
{ %>
<a href=
"<%= item.Id %>">
<%= item.Title.Text %></a><br />
<% } %>
</div>
</div>
</body>
</html>
三、Area 的 Demo
Areas/AsynchronousController/AsynchronousControllerAreaRegistration.cs
/*
* ASP.NET MVC 2.0 - 对 Area 的支持,其容许在一个应用程序内实现多套 MVC
* 一、新建 Area:右键 -> Add -> Area...
* 二、继承 AreaRegistration,配置对应此 Area 的路由
* 三、在 Global 中经过 AreaRegistration.RegisterAllAreas(); 注册此 Area
* 四、有了 Area,就必定要配置路由的命名空间
*/
using System.Web.Mvc;
namespace MVC20.Areas.AsynchronousController
{
// 新建一个 Area 会自动生成这个继承自 AreaRegistration 的类
// 若是须要使用此 Area 下的 MVC, 须要在 Global 中 AreaRegistration.RegisterAllAreas();
public
class AsynchronousControllerAreaRegistration : AreaRegistration
{
public override
string AreaName
{
get
{
return
"AsynchronousController";
}
}
override void RegisterArea() override void RegisterArea(AreaRegistrationContext context)
{
// 在 Area 中配置路由的时候,要设置命名空间(即本例中的第 4 个参数)
context.MapRoute(
"AsynchronousController_default",
"AsynchronousController/{controller}/{action}/{id}",
new { controller =
"Home", action =
"Index", id = UrlParameter.
Optional }, // Parameter defaults
new
string[] {
"MVC20.Areas.AsynchronousController.Controllers" }
);
}
}
}
Global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MVC20
{
public
class MvcApplication : System.Web.HttpApplication
{
static void RegisterRoutes() static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}");
// 用于本项目中使用了 Area,因此在配置路由的时候,要设置命名空间(即本例中的第 4 个参数)
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL
with parameters
new { controller =
"Home", action =
"Index", id = UrlParameter.
Optional }, // UrlParameter.
Optional - 若是从url路由中没法获取某个参数的值,则从url参数中获取该参数的值
new
string[] {
"MVC20.Controllers"}
);
}
void Application_Start() void Application_Start()
{
// 注册本应用程序中的全部 Area
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
}
}
四、对 DataAnnotations 的支持,实现数据验证(包括客户端验证)
Metadata.cs
/*
* ASP.NET MVC 2.0 - 对 DataAnnotations 的支持,能够实现验证及 Scaffold
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace MVC20.Models
{
[MetadataType(typeof(ProductCategory_Metadata))]
public partial
class ProductCategory
{
}
public
class ProductCategory_Metadata
{
[Required(AllowEmptyStrings =
false, ErrorMessage =
"{0} 为必填字段")]
[NameValidation(ErrorMessage =
"{0} 只能是数字")]
[Display(Name=
"名称")]
public
string Name;
[ScaffoldColumn(
false)]
public object ModifiedDate {
get;
set; }
// DisplayValue=
true - 默认值。在显示模板中,用一个 lable 显示指定的值;在编辑模板中,用一个 lable 显示指定的值,并用一个 hidden input 保存该值
// DisplayValue=
false - 在显示模板中,不作任何显示;在编辑模板中,不作任何显示,但会用一个 hidden input 保存该值
[System.Web.Mvc.HiddenInput(DisplayValue=
true)]
public object rowguid {
get;
set; }
}
// 经过继承 RegularExpressionAttribute 实现自定义验证 Attribute
// 经过继承 ValidationAttribute 实现自定义验证 Attribute 的 Demo 能够参看 http://webabcd.blog.51cto.com/1787395/341156
public
class NameValidationAttribute : RegularExpressionAttribute
{
NameValidationAttribute() NameValidationAttribute()
: base(
"^[0-9]*$")
{
}
}
}
CategoryController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVC20.Models;
using System.ComponentModel;
namespace MVC20.Controllers
{
public
class CategoryController : Controller
{
// DefaultValueAttribute - 用于为参数指定默认值。当路由或url参数中无此参数时,则会使用此默认值
ActionResult Index() ActionResult Index([DefaultValue(2)]int pageIndex)
{
int pageSize = 10;
var categories =
new Models.CategorySystem().GetCategory(pageIndex, pageSize);
return View(
"Index", categories);
}
ActionResult Edit() ActionResult Edit(int id)
{
var category =
new Models.CategorySystem().GetCategory(id);
return View(
"Edit", category);
}
// 用于演示实现 Model 级别的 Dynamic Data
[HttpPost]
ActionResult Edit() ActionResult Edit(int id, FormCollection formValues)
{
var cs =
new Models.CategorySystem();
var category = cs.GetCategory(id);
TryUpdateModel<ProductCategory>(category);
cs.Save();
return RedirectToAction(
"Index");
}
ActionResult Edit2() ActionResult Edit2(int id)
{
var category =
new Models.CategorySystem().GetCategory(id);
return View(
"Edit2", category);
}
// 用于演示实现 Property 级别的 Dynamic Data
[HttpPost]
ActionResult Edit2() ActionResult Edit2(int id, FormCollection formValues)
{
var cs =
new Models.CategorySystem();
var category = cs.GetCategory(id);
TryUpdateModel<ProductCategory>(category);
cs.Save();
return RedirectToAction(
"Index");
}
ActionResult Details() ActionResult Details(int id)
{
var category =
new Models.CategorySystem().GetCategory(id);
return View(
"Details", category);
}
ActionResult Create() ActionResult Create()
{
ProductCategory category =
new ProductCategory()
{
};
return View(category);
}
// 用于演示经过 DataAnnotations 实现数据验证
[HttpPost]
ActionResult Create() ActionResult Create(ProductCategory category)
{
if (!ModelState.IsValid)
{
return View(category);
}
else
{
var cs =
new Models.CategorySystem();
cs.AddCategory(category);
cs.Save();
return View(
"Details", category);
}
}
}
}
Create.aspx
<%@ Page Title=
"" Language="C#
" MasterPageFile="~/Views/Shared/Site.Master
" Inherits="System.Web.Mvc.ViewPage<MVC20.Models.ProductCategory>" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"TitleContent" runat=
"server">
Create
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"MainContent" runat=
"server">
<!--
为了实现客户端验证,须要引用如下两个 JavaScript
-->
<script src=
"http://www.cnblogs.com/Scripts/MicrosoftAjax.js" type=
"text/javascript"></script>
<script src=
"http://www.cnblogs.com/Scripts/MicrosoftMvcValidation.js" type=
"text/javascript"></script>
<h2>Create</h2>
<!--启用客户端验证功能-->
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<!-- Html.ValidationSummary Helper Method Can Display Model-Level Errors -->
<%: Html.ValidationSummary(
"错误信息以下:")%>
<fieldset>
<legend>Fields</legend>
<div
class=
"editor-label">
<%: Html.LabelFor(model => model.ProductCategoryID) %>
</div>
<div
class=
"editor-field">
<%: Html.TextBoxFor(model => model.ProductCategoryID) %>
<!--
验证的错误信息来自 DataAnnotations,也能够经过 ValidationMessageFor() 来指定须要显示的错误信息
-->
<%: Html.ValidationMessageFor(model => model.ProductCategoryID,
"*") %>
</div>
<div
class=
"editor-label">
<%: Html.LabelFor(model => model.ParentProductCategoryID) %>
</div>
<div
class=
"editor-field">
<%: Html.TextBoxFor(model => model.ParentProductCategoryID) %>
<%: Html.ValidationMessageFor(model => model.ParentProductCategoryID) %>
</div>
<div
class=
"editor-label">
<%: Html.LabelFor(model => model.Name) %>
</div>
<div
class=
"editor-field">
<%: Html.TextBoxFor(model => model.Name) %>
<%: Html.ValidationMessageFor(model => model.Name) %>
</div>
<div
class=
"editor-label">
<%: Html.LabelFor(model => model.rowguid) %>
</div>
<div
class=
"editor-field">
<%: Html.TextBoxFor(model => model.rowguid) %>
<%: Html.ValidationMessageFor(model => model.rowguid) %>
</div>
<div
class=
"editor-label">
<%: Html.LabelFor(model => model.ModifiedDate) %>
</div>
<div
class=
"editor-field">
<%: Html.TextBox(
"ModifiedDate", DateTime.Now.ToString(
"yyyy-MM-dd")) %>
<%: Html.ValidationMessageFor(model => model.ModifiedDate) %>
</div>
<p>
<input type=
"submit" value=
"Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink(
"Back to List",
"Index") %>
</div>
</asp:Content>
五、MVC 与 Dynamic Data 相结合的 Demo
相关的 DataAnnotations 就用上面的那个
Category/Edit.aspx
<%@ Page Title=
"" Language="C#
" MasterPageFile="~/Views/Shared/Site.Master
" Inherits="System.Web.Mvc.ViewPage<MVC20.Models.ProductCategory>" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"TitleContent" runat=
"server">
Edit
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"MainContent" runat=
"server">
<h2>
Edit</h2>
<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(
"错误信息以下:")%>
<%= Html.EditorFor(category => category) %>
<input type=
"submit" value=
"Save" />
<% } %>
<div>
<%: Html.ActionLink(
"Back to List",
"Index") %>
</div>
</asp:Content>
Category/Edit2.aspx
<%@ Page Title=
"" Language="C#
" MasterPageFile="~/Views/Shared/Site.Master
" Inherits="System.Web.Mvc.ViewPage<MVC20.Models.ProductCategory>" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"TitleContent" runat=
"server">
Edit2
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"MainContent" runat=
"server">
<h2>Edit2</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(
"错误信息以下:")%>
<fieldset>
<legend>Fields</legend>
<%= Html.LabelFor(c => c.ParentProductCategoryID) %>: <%= Html.EditorFor(c => c.ParentProductCategoryID)%>
</br>
<%= Html.LabelFor(c => c.Name) %>: <%= Html.EditorFor(c => c.Name)%>
<p>
<input type=
"submit" value=
"Save" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink(
"Back to List",
"Index") %>
</div>
</asp:Content>
Category/Index.aspx
<%@ Page Title=
"" Language="C#
" MasterPageFile="~/Views/Shared/Site.Master
" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MVC20.Models.ProductCategory>>" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"TitleContent" runat=
"server">
Index
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"MainContent" runat=
"server">
<h2>
Index</h2>
<table>
<tr>
<th>
</th>
<th>
ProductCategoryID
</th>
<th>
ParentProductCategoryID
</th>
<th>
名称
</th>
<th>
rowguid
</th>
<th>
ModifiedDate
</th>
</tr>
<% foreach (var item
in Model)
{ %>
<tr>
<td>
<%: Html.ActionLink(
"Edit",
"Edit",
new { id=item.ProductCategoryID }) %>
|
<%: Html.ActionLink(
"Details",
"Details",
new { id=item.ProductCategoryID })%>
|
<%: Html.ActionLink(
"Delete",
"Delete",
new { id=item.ProductCategoryID })%>
</td>
<td>
<%: item.ProductCategoryID %>
</td>
<td>
<%: item.ParentProductCategoryID %>
</td>
<td>
<%: Html.DisplayTextFor(c => item.Name)%>
</td>
<td>
<%: item.rowguid %>
</td>
<td>
<!--
Html.DisplayFor() - 能够指定显示模板(能够指定 Property 级模板,也能够指定 Model 级模板),本例的模板地址为 Views/Shared/DisplayTemplates/MyDate.ascx ,这种实现方式来自 Dynamic Data
-->
<%= Html.DisplayFor(Product => item.ModifiedDate,
"MyDate")%>
</td>
</tr>
<% } %>
</table>
<p>
<%= Html.RouteLink(
"上一页",
"Default",
new { pageIndex = Convert.ToInt32(Request.QueryString[
"pageIndex"] ??
"2") - 1 })%>
|
<%= Html.RouteLink(
"下一页",
"Default",
new { pageIndex = Convert.ToInt32(Request.QueryString[
"pageIndex"] ??
"2") + 1 })%>
</p>
<p>
<%: Html.ActionLink(
"Create New",
"Create") %>
</p>
</asp:Content>
Shared/DisplayTemplates/MyDate.ascx
<%@ Control Language=
"C#"
Inherits=
"System.Web.Mvc.ViewUserControl<dynamic>" %>
<%= Html.Encode(
String.Format(
"{0:yyyy-MM-dd}", Model)) %>