`
feiliboos
  • 浏览: 672858 次
文章分类
社区版块
存档分类
最新评论

asp.net mvc 学习

 
阅读更多

相对其他的资料,这个系列的文章说了很多原理的东西,我喜欢,呵呵。

转载地址:

http://www.cnblogs.com/jasenkin/archive/2010/09/11/mvc_action_filter.html

了解关于 ASP.NET MVC 应用程序与ASP.NET Web Forms 应用程序两者之间的不同点. 了解怎样去决定什么时候创建一个 ASP.NET MVC 应用程序.

ASP.NET MVC 概述(C#)

模型-视图-控制 (MVC) 结构模式将一个应用程序分隔成三个主要组成部分:模型层、视图层、控制器。ASP.NET MVC框架提供了另一种可以替代ASP.NET Web Forms模式的选择来创造基于MVC的 web应用程序。ASP.NET MVC 框架是一个轻量级的框架,它与现有的ASP.NET特征相集成,比如母板页与基于身份的验证。MVC框架下定义在System.Web.Mvc命名空间中。

   MVC是许多开发者都很熟悉的标准设计模式。很多类型的Web应用程序将会受益于MVC框架。一部分将依旧会继续使用传统的基于Web Forms和回传的ASP.NET应用程序模式。其他类型的 Web应用程序将这两种方法相结合使用:两者互不排斥。
  
   MVC框架包含以下组成部分:
  
   •模型层。模型对象是应用程序的一部分,它实现了应用程序的数据定义的逻辑。通常,模型对象检索和储了在数据库中的模型状态。例如,一个Products对象可以在数据库检索信息,操作它,然后将修改的信息更新回SQL服务器中的Products表。

   在小应用程序中,该模型常常是一个概念性的分离而不是物理上的。例如,如果应用程序仅仅读取数据集和将它发送到视图上,应用程序将不存存在一个物理模型层及相关的类。在这种情况下,数据集将具有一个模型对象的角色。
  
  
   •视图层。视图层是显示应用程序的用户界面(UI)的部分。通常,用户界面UI是由模型数据所创建的。
  
  
   •控制层。控制层是处理用户交互,对模型层起作用,并最终选择一个视图view来呈现那个显示的用户界面的部分。在一个MVC应用程序中,视图层view只显示信息,控制层controller处理并响应用户的输入和交互。例如,控制层处理查询字符串的值,并将这些值传递给模型层model,该模型层就会反过来使用这些值来查询数据库。


   MVC模式帮助你创建应用程序,它将应用程序的不同方面的(输入逻辑、业务逻辑,和UI逻辑)进行分离,同时在这些元素之间提供一个松耦合关系。这种模式指定了每一种逻辑在应用程序中所处的位置。UI逻辑属于视图层。输入逻辑属于控制层。业务逻辑属于模型层。当你创建一个应用程序时,这种分离能帮助你处理复杂事务,因为它可以让您每一次专注于实施的一个方面。例如,你可以专注于视图层,而不依赖任何业务逻辑。
  
   除了管理复杂的事务,MVC模式比基于Web Forms的ASP.NET Web应用程序更加容易进行测试。例如,在一个基于Web Forms的ASP.NET Web应用程序,一个单一的类被用于显示输出和响应用户的输入。因为测试单个页面,你必须实例化这个页面page类,它所有的子控件以及应用程序中额外的依赖类,所以针对于基于Web Forms的 ASP.NET应用程序写的自动测试将可能很复杂。因为有那么多类被实例化用来运行这个页面,它可能很难写出针对于应用程序的单个部分的测试代码。因此,基于Web Forms的ASP.NET Web应用程序的测试比MVC应用程序更难实现。而且,基于Web Forms的ASP.NET Web应用程序需要一个Web服务器。MVC框架将这些组成部分进行解耦,大量的使用接口,使它能够独立的测试单独的部分。
   同样,MVC应用程序中的介于三个主要组成部分的松耦合也促进了平行开发。例如,一个开发者可以开发视图层,另一个开发者可以开发控制逻辑层,第三个开发者可以专注于模型层中的商业逻辑。

决定什么时候去创造一个MVC应用程序
  你必须仔细考虑是否要通过采用ASP.NET MVC框架和ASP.NET Web Forms模型中任何一种来实施一个Web应用程序。MVC框架取代Web Forms模型;你能够为Web应用程序采用任何一种框架。
  在你为一个具体的Web站点决定采用MVC框架还是Web Forms模型之前,权衡一下每一种方法的优势。


  基于MVC的Web应用程序的优势
  这个ASP.NET MVC框架提供了以下优点:
  
  它通过将应用程序分解为模型层,视图层和控制层来使我们更容易管理复杂的事务。
  它不使用视图状态或基于服务器的表单。这使得MVC框架非常适合于那些想完全控制应用程序行为的开发者。
  它使用一个 Front Controller模式,它通过一个单一的控制器来处理Web应用程序请求。这使你能设计一个支持丰富的路由基础设施的应用程序。更多信息,在MSDN网站查询Front Controller。
  它提供更好的驱动测试开发的支持(TDD)。
  它适用于需要高度控制程序行为的开发者和网站设计者支持的应用程序的大型团队。

  

基于Web Forms的Web应用程序的优点
  基于Web Forms的框架提供以下优点:
  
  它支持一个能够在HTTP之上保持状态的事件模型,从而有利于line-of-business网页应用软件的开发。基于Web Forms的Web应用程序提供了被数以百计的服务器控件支持的许多事件。
  它使用一个能够增加函数到单个页面的页面控制模式,。更多信息,见MSDN网站中的Page Controller。
  它使用视图状态或基于服务器的表单,它可以使管理状态信息更加容易。
  它适用于那些网站开发者和设计师想利用大量组件来快速应用开发的小团队。
  总的来说,应用软件的开发不是那么复杂,因为组件(页类、控件等)是紧密结合在一起,通常比MVC模型需要更少的代码。


  ASP.NET MVC 框架的特点
  ASP.NET MVC 框架提供了以下特点:
  分离的应用程序任务(输入逻辑、业务逻辑,和UI逻辑)、可测性、默认的驱动测试开发(TDD)。所有在MVC框架中的核心是interface-based和可以利用模拟对象进行测试,模拟对象能够模拟实际应用中对象的真实行为。你不一定需要在ASP.NET进程中运行控制层就能够对应用程序进行单元测试,它使得单元测试更快速和灵活。你可以使用任何兼容.net框架的单元测试框架。
  一个可扩展和可插接的框架。这个ASP.NET MVC框架的组件被设计过,这样它们就能够方便地更换或自定义。你可以插入你自己的视图引擎,URL路由策略,action-method参数的序列化以及其他组件。这个 ASP.NET MVC 框架也支持使用依赖性注射(DI)和控制反转(IOC)容器模型。DI允许您注入对象到一个类中,而不是依赖这个类来创建对象本身。IOC规定,如果一个对象需要另一个对象,第一个对象应该得到来自外部源(如一个配置文件)的第二个对象。这使得测试更容易。
  一个强大的URL-mapping组件,它让你建立拥有可理解并且可搜索的URL的应用程序。URL并不需要包括文件扩展名,是设计用来支持URL命名模式, 这种模式对于搜索引擎优化(SEO)和表述性状态转移(REST)寻址能够很好的运行。
  支持现有的ASP.NET 功能。ASP.NET MVC让你使用功能,如表格认证和Windows认证、URL的授权,成员和角色,输出和数据缓存,会话和状态管理等。

<!--done-->

理解MVC应用程序执行过程

基于ASP.NET MVC Web应用程序的请求首先通过一个UrlRoutingModule的对象(HTTP模块)。这个模块匹配请求,并且执行路由选择。这个UrlRoutingModule对象选择第一个匹配当前请求的路由对象。如果没有路径匹配,这个UrlRoutingModule什么也不做,让这个请求返回给常规的ASP.NET或者IIS来请求处理。

从这个被选中的Route对象,UrlRoutingModule对象获得IRouteHandler对象(IRouteHandler对象与Route对象是相互关联的)。一般来说,在一个MVC应用程序中,它将是MvcRouteHandler实例。这个IRouteHandler实例创建一个IHttpHandler对象,并且将它传递给IHttpContext对象。默认情况下,MVC IHttpHandler实例就是MvcHandler对象。然后,这个MvcHandler对象选择controller,controller将最终提交这个请求。


  这个module 和 handler是ASP.NET MVC框架的入口点。它们执行下列行为:
  
  选择合适的controller。
  获得一个具体controller实例。
  调用controller的执行方法。
  
  下表列出了一个MVC Web项目的执行的各阶段。

阶段 详细
接收应用程序的第一次请求 在Global.asax文件中, Route对象 被添加到RouteTable对象.
执行路由选择 UrlRoutingModule 模块使用第一个在RouteTable 集合中匹配的Route 对象来创建RouteData对象, 然后它将使用这个RouteData对象来创建RequestContext (IHttpContext)对象.
创建MVC request handler MvcRouteHandler 创建MvcHandler类的一个实例,并且将它传递给RequestContext实例.
创建controller MvcHandler对象使用RequestContext实例来确认IControllerFactory 对象(DefaultControllerFactory类的一个实例) ,以用来创建conteoller实例。
执行controller MvcHandler 实例调用controller的执行method.
调用action 大部分controllers 继承自Controller基础类. 与controller相关联的ControllerActionInvoker 对象决定这个controller类的哪个方法将被调用 , 然后再调用那个方法.
执行result 一个典型的action 方法可能接收用户输入,准备合适的响应数据, 然后通过返回一个result的类型来执行这个result. 这个内置的能够执行的result 类型 包含以下类型: ViewResult (它呈现一个视图,并且是最常用的result类型), RedirectToRouteResult, RedirectResult, ContentResult, JsonResult以及EmptyResult.

ASP.NET MVC Routing概述

ASP.NET Routing模块的责任是将传入的浏览器请求映射为特有的MVC controller actions。

使用默认的Route Table
当你创建一个新的ASP.NET MVC应用程序,这个应用程序已经被配置用来使用ASP.NET Routing。 ASP.NET Routing 在2个地方设置。第一个,ASP.NET Routing 在你的应用程序中的Web配置文件(Web.config文件)是有效的。在配置文件中有4个与routing相关的代码片段:system.web.httpModules代码段,system.web.httpHandlers 代码段,system.webserver.modules代码段以及 system.webserver.handlers代码段。千万注意不要删除这些代码段,如果没有这些代码段,routing将不再运行。第二个,更重要的,route table在应用程序的Global.asax文件中创建。这个Global.asax文件是一个特殊的文件,它包含ASP.NET 应用程序生命周期events的event handlers。这个route table在应用程序的起始event中创将。

在Listing 1中包含ASP.NET MVC应用程序的默认Global.asax文件.

Listing 1 - Global.asax.cs

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1publicclassMvcApplication:System.Web.HttpApplication
2{
3publicstaticvoidRegisterRoutes(RouteCollectionroutes)
4{
5routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6routes.MapRoute(
7"Default",//路由名称
8"{controller}/{action}/{id}",//带有参数的URL
9new{controller="Home",action="Index",id=UrlParameter.Optional}//参数默认值
10);
11
12}
13
14protectedvoidApplication_Start()
15{
16AreaRegistration.RegisterAllAreas();
17
18RegisterRoutes(RouteTable.Routes);
19}
20}

当一个MVC应用程序第一个启动,Application_Start() 方法被调用,这个方法反过来调用RegisterRoutes() 方法。

这个默认的route table包含一个单一的route。这个默认的route将url的第一个段映射为一个controller名称,url的第二个段映射为一个controller action,第三个段映射为命名为id的参数。
假如,你在网页浏览器的地址栏中键入下面的url:/Home/Index/3,这个默认的route将这个url映射为下面的参数:
controller = Home controller名称

action = Index controller action

id = 3 id的参数

当你请求/Home/Index/3这样的url,下面的代码将执行。HomeController.Index(3)

这个默认的route包含3个默认的参数。如果你没有提供一个 controller,那么 controller默认为Home。同样,action默认为Index,id参数默认为空字符串。
让我们来看一些关于默认的route怎么映射urls为controller actions的例子。假如你在你的浏览器地址栏中输入如下的url:/Home,由于这些默认的route参数有一些相关的默认值,键入这样的URL,将导致HomeController类的Index()方法(如Listing 2)被调用。

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1namespaceMvcRoutingApp.Controllers
2{
3[HandleError]
4publicclassHomeController:Controller
5{
6publicActionResultIndex(stringid)
7{
8ViewData["Message"]="欢迎使用ASP.NETMVC!";
9
10returnView();
11}
12
13publicActionResultAbout()
14{
15returnView();
16}
17}
18}
19
20

在Listing 2中,这个HomeController 类包含一个名为Index()的方法。这个URL /Home导致Index()方法被调用,一个空的字符串将作为id参数的值。由于mvc框架调用controller actions的这种方式,这个URL /Home同样匹配HomeController类中的Index()方法(如Listing 3)。
Listing 3 - HomeController.cs (Index action with no parameter)

[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}

在Listing 3中,这个Index()方法不接收任何参数。这个URL /Home将导致Index()方法被调用。URL /Home/Index/3同样调用这个方法(ID被忽略)。


Listing 4 - HomeController.cs (Index action with nullable parameter)


[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int? id)
{
return View();
}
}

在Listing 4中, Index() 方法有一个整数参数. 由于这个参数是可空参数 , Index() 将被调用而不引起错误.

最后, 使用 URL /Home 来调用如Listing 5中的Index() 方法 将导致异常,因为这个ID参数不是一个可空的参数。如果你试图去调用这个Index()方法,你将获得如下图所示的错误。

Listing 5 - HomeController.cs (Index action with Id parameter)
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int id)
{
return View();
}
}

另一方面,使用如Listing 5中的Index controller action,URL /Home/Index/3运行正常。Index controller action in Listing 5. /Home/Index/3请求将导致Index()方法被调用,ID参数拥有一个3的值。

总结


这是一个关于ASP.NET Routing的简要介绍. 应该了解了这个默认的route如何将URLs映射为controller actions。


创建自定义的Routes (C#)

这个教程,你将学会怎样添加一个自定义的route到一个asp.net mvc应用程序。你将学会在Global.asax文件中,怎样使用一个自定义的route来修改这个默认的route table。
对于许多简单的ASP.NET MVC 应用程序,这个默认的route table将运行得很好。然而,你可能发现,你可能特定的routing 需求。那样的话,你可能需要创建一个自定义的route。
设想一下,例如,你正在建立一个博客应用程序,你可能想要去处理像/Archive/12-25-2009的输入请求。


当一个用户键入这个请求,你想要返回与日期为12/25/2009相符的博客实体。为了处理这种类型的请求,你需要去创建一个自定义的route。
在 Listing 1中,这个Global.asax文件中包含一个新的名为Blog的自定义route,它处理类似于/Archive/entry date的请求。
Listing 1 - Global.asax (with custom route)

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->1usingSystem;
2usingSystem.Collections.Generic;
3usingSystem.Linq;
4usingSystem.Web;
5usingSystem.Web.Mvc;
6usingSystem.Web.Routing;
7
8namespaceMvcRoutingApp
9{
10//注意:有关启用IIS6或IIS7经典模式的说明,
11//请访问http://go.microsoft.com/?LinkId=9394801
12
13publicclassMvcApplication:System.Web.HttpApplication
14{
15publicstaticvoidRegisterRoutes(RouteCollectionroutes)
16{
17routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
18routes.MapRoute(
19"Blog",//路由名称
20"Archive/{entryDate}/{id}",//带有参数的URL
21new{controller="Archive",action="Entry",id=UrlParameter.Optional}//参数默认值
22);
23routes.MapRoute(
24"Default",//路由名称
25"{controller}/{action}/{id}",//带有参数的URL
26new{controller="Home",action="Index",id=UrlParameter.Optional}//参数默认值
27);
28
29}
30
31protectedvoidApplication_Start()
32{
33AreaRegistration.RegisterAllAreas();
34
35RegisterRoutes(RouteTable.Routes);
36}
37}
38}

你添加到route table的routes的顺序是很重要的。我们新自定义的blog route在现存的默认route之前添加。如果你颠倒了顺序,那么这个默认的route总是先调用而不是这个自定义的route。
这个自定义的blog toute匹配任何以 /Archive/ 开头的请求。所以,它匹配所有下列URLs:
/Archive/12-25-2009

/Archive/10-6-2004

/Archive/apple

这个自定义的route将输入的请求映射至名为Archive的controller,并且调用 Entry() action。当 Entry() action被调用的时候,这个输入的日期被当作名为entryDate的参数。
Listing 2 - ArchiveController.cs
public class ArchiveController : Controller
{

public string Entry(DateTime entryDate)
{
return "You requested the date:" + entryDate.ToString();
}

}

注意,在Listing 2中这个Entry()方法接收一个类型为DateTime的参数。MVC框架是足够智能的,它自动将URL中输入的date转换为一个DateTime值。如果URL中输入的date不能转换为DateTime,错误将被引发。

总结
这个教程演示怎样来创建一个自定义的route。你学会了怎样在Global.asax 文件中添加一个自定义的route到route table。我们讨论了怎样为blog实体将请求映射为名为ArchiveController的controller,名为Entry()的controller action

创建一个路由约束(C#)

你能够使用路由约束来限制匹配一个特殊路径的浏览器请求。你能够使用一个正则表达式来制定一个路由约束。
例如,假设你已经定义路由如下:

Listing 1 - Global.asax.cs

routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"}
);

Listing 1 包含一个命名为Product的路由. 你能够使用这个 Product route来将将浏览器请求映射到ProductController,如下:

Listing 2 - Controllers/ProductController.cs

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
public class ProductController : Controller
{

public ActionResult Details(int productId)
{
return View();
}

}
}

注意:Details() action 接收一个命名为 productId的单一参数. 这个参数是整型参数.

在Listing 1 will中定义的route将匹配一下的任何一个URLs:

?/Product/23
?/Product/7
遗憾的,这个route也同样匹配以下的URLs:

?/Product/blah
?/Product/apple

因为Details() action预期接收一个整型的参数,当请求中包含的内容不同于整数时,它将导致一个错误。

你真正想要做的,仅仅是匹配包含一个的整数productId的URLs。当你定义一个route时,你能够使用一个限制条件来限制URLs,使它匹配这个route。在Listing 3中,这个route包含一个只匹配整数的正则表达式约束。

Listing 3 - Global.asax.cs

routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"},
new {productId = @"/d+" }
);

这个真正表达式约束/d+ 匹配一个或多个整数. 这个约束导致Product route匹配如下的URLs:

?/Product/3
?/Product/8999

但不是如下的URLs:

?/Product/apple
?/Product

这个浏览器请求将被另一个route处理。或者,如果没有匹配的routes, “The resource could not be found ”错误将被返回.

创建一个自定义路由约束 (C#)

演示如何创建一个自定义的路由约束.约束接口中的Match方法如下:

IRouteConstraint.Match Method
bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)


你可以通过实现IRouteConstraint接口来创建一个路径约束,并且通过几个步骤把它添加到你的路径中。IRouteConstraint仅有一个Match方法,它返回一个布尔值。这个布尔值决定该请求是否应该被route对象处理。

如何创建一个ASP.NET MVC应用程序来模拟一个仅仅在视图中显示年份,月份,日期的文章系统,类似于博客系统的路径?

(一)首先,创建一个ArchiveController,它包含一个仅仅显示年份,月份,日期值的Index action 方法。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->namespaceMvcAppRouting.Controllers
{
publicclassArchiveController:Controller
{
//
//GET:/Archive
publicActionResultIndex(intyear,intmonth,intday)
{
ViewData[
"Year"]=year;
ViewData[
"Month"]=month;
ViewData[
"Day"]=day;
returnView();
}
}
}

(二)创建一个显示数据的view。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --><%@PageTitle=""Language="C#"MasterPageFile="~/Views/Shared/Site.Master"Inherits="System.Web.Mvc.ViewPage"%>
<asp:ContentID="Content1"ContentPlaceHolderID="TitleContent"runat="server">
Index
</asp:Content>
<asp:ContentID="Content2"ContentPlaceHolderID="MainContent"runat="server">
<h2>Index</h2>
<fieldset>
<legend>Fields</legend>
<p>Year:
<%=ViewData["Year"]%>
</p><p>
Month:
<%=ViewData["Month"]%>
</p><p>
Day:
<%=ViewData["Day"]%></p>
</fieldset>
</asp:Content>

(三)最主要的步骤,需要创建年份,月份,日期验证的三个分离的约束。它们将在路径定义中应用。以创建一个DayConstraint来开始。

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->usingSystem.Web.Routing;
usingSystem.Globalization;

namespaceMvcAppRouting.RouteConstraints
{
publicclassDayConstraint:System.Web.Routing.IRouteConstraint
{
publicboolMatch(HttpContextBasehttpContext,Routeroute,stringparameterName,RouteValueDictionaryvalues,RouteDirectionrouteDirection)
{
if((routeDirection==RouteDirection.IncomingRequest)&&(parameterName.ToLower(CultureInfo.InvariantCulture)=="day"))
{
try{
intmonth=int.Parse(values["Month"].ToString());
intday=int.Parse(values["Day"].ToString());
if(month<=0||month>12)returnfalse;
if(day<1)returnfalse;
switch(month)
{
case1:
case3:
case5:
case7:
case8:
case10:
case12:
if(day<32)returntrue;
break;
case2:
if(day<29)returntrue;
break;
case4:
case6:
case9:
case11:
if(day<31)returntrue;
break;
}
}
catch{
returnfalse;
}
}
returnfalse;
}
}
}

年份数据限制为1950-2010。同样,月份的值在1-12之间,此处不再叙述,详见源代码。

(四)最后一步是将所有的联系在一起,使ASP.NET MVC 应用程序能够运行。这里仅仅是定义一个routes。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->namespaceMvcAppRouting
{
//注意:有关启用IIS6或IIS7经典模式的说明,
//请访问http://go.microsoft.com/?LinkId=9394801

publicclassMvcApplication:System.Web.HttpApplication
{
publicstaticvoidRegisterRoutes(RouteCollectionroutes)
{
routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",//路由名称
"{controller}/{action}/{id}",//带有参数的URL
new{controller="Home",action="Index",id=UrlParameter.Optional}//参数默认值
);

routes.MapRoute(
"Archive",
"archive/{year}/{month}/{day}",
new
{
controller
="Archive",
action
="Index",
year
="",
month
="",
day
=""
},
new
{
year=newRouteConstraints.YearConstraint(),
month=newRouteConstraints.MonthConstraint(),
day=newRouteConstraints.DayConstraint()
}
);
}
protectedvoidApplication_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);
}
}
}


实例中的“archive/{year}/{month}/{day}”模式,像正常的routes一样,同样为route设置了默认的值,并且增加了一个约束对象。这个约束对象将模式中的参数映射至它的约束实例中,因此这些值能够被验证。

现在我用一个验证的请求模式来运行这个应用程序,展示的页面如下。

同样,发送一个archive/2000/2/30这个请求,它是不能通过验证,并且得到一个错误。

总结:
应该注意约束条件必须继承IRouteConstraint,并且实现Match方法

创建一个自定义action必须满足的要求

方法必须为公共的.
方法不能为静态方法.
方法不能是Control基类中的方法(如:ToString,GetHashCode等)

方法不能为扩展方法.
方法不能为一个构造函数 ,getter, setter.
方法不能包含ref 或 out 参数.

使用 NonActionAttribute 特性将阻止该action被调用

namespaceMVCViewAndAction.Web.Controllers
{
[HandleError]
publicclassUserDemoController:Controller
{
//
//GET:/UserDemo/
//自定义一个简单的方法
[NonAction]
//publicsealedclassNonActionAttribute表示一个特性,该特性用于指示控制器方法不是操作方法。
publicstringDisplayString()
{
return"thisisademostring!";
}
}
}

理解Views

相对于ASP.NET与 Active Server Pages, ASP.NET MVC 并不包含任何直接对应的一个页面。在ASP.NET MVC 应用程序中,你键入浏览器地址栏中的URL在磁盘上并没有相应的一个页面,该URL被映射为controller actions。与页面page最相近的正是我们所说的View。

最基本的如下:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicActionResultIndex()
{
returnView();
}

为了探究view的本质,以显示如下的结果:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicclassUserDemoController:Controller
{
publicRssActionResultRssShow()
{
returnnewRssActionResult();
}
}

我们需要创建一个继承ActionResult的RssActionResult类,如下所示:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->namespaceMVCViewAndAction.Common
{
/*
*System.Web.Mvc
publicabstractclassActionResult
{
protectedActionResult();
publicabstractvoidExecuteResult(ControllerContextcontext);
}
*/
publicclassRssActionResult:ActionResult
{
publicRssActionResult()
{
}
//
publicoverridevoidExecuteResult(ControllerContextcontext)
{
if(context==null)
{
thrownewArgumentNullException("ControllerContextisnull!");
}
HttpResponseBaseresponse
=context.HttpContext.Response;
Rssrss
=newRss();
rss.CreateSampleRss(response);
}
}

通过从 System.Web.Mvc.ActionResult 类继承的自定义类型,ExecuteResult(ControllerContextcontext)启用对操作方法结果的处理。

附:ExecuteResult()中的rss.CreateSampleRss(response)方法通过利用HttpResponseBase来处理响应流。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicvoidCreateSampleRss(HttpResponseBaseresponse)
{
XmlTextWriterwriter
=newXmlTextWriter(response.OutputStream,System.Text.Encoding.UTF8);
WriteRssHeader(writer);
for(inti=0;i<50;i++)
{
WriteRssItem(writer,
"demotitle:jasenkin"+i.ToString(),http://jasenkin/,"decription:--->"+i.ToString());
}
WriteRssBottom(writer);
writer.Flush();
writer.Close();
response.ContentEncoding
=System.Text.Encoding.UTF8;
response.ContentType
="text/xml";
response.Cache.SetCacheability(HttpCacheability.Public);
response.End();
}

执行结果如下:

一个典型的Action可能接收用户输入,准备合适的响应数据, 然后通过返回一个Result的类型(如上例中的RssActionResult),系统将自动调用这个Result类型(如上例中的RssActionResult)的ExecuteResult(context)来响应浏览器请求,呈现的就是我们所说的View了(如上图)。

这仅仅是一个继承自actionresult的自定义类,其中的ExecuteResult()方法才是该类的关键之处

理解 Action Filters

Action filter 是能够应用于controller action --或整个controller的一个特性,它们的基类为System.Web.Mvc.FilterAttribute 。它限定了action执行的方式。ASP.NET MVC框架包含数个action filters。

  • HandleError – 这个action 过滤器处理controller action执行时出现的错误。
  • OutputCache – 这个action 过滤器将 controller action的输出缓存一段制定的时间 .
  • Authorize – 这个action 过滤器使你能够限制特定的用户或角色的访问.

使用Action Filter

action filter是一个特性. 你能够应用大部分的action filters 在单个的controller action 或者整个controller上.

例如下面的Data controller有一个返回当前时间的Index()方法.这个action拥有OutputCache action filter. 这个过滤器导致由action返回的值能够缓存10秒钟.

VaryByParam 属性使用的设置不建议通过设置“*”的值来使用所有参数进行区分。这可能会导致缓存溢出。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicclassDataController:Controller
{
//
//GET:/Data/
[OutputCache(Duration=20,VaryByParam="")]
publicstringIndex()
{
returnDateTime.Now.ToString();
}
}

如果你重复调用Index() action(不断刷新当前页面), 那么你将看到当前的内容在Duration=20秒内是不变的.

一个单一的action filter – OutputCache action filter – 被应用于Index() 方法. 同样,你可以应用多个action filters 在同一个action上.

不同类型的Filters

ASP.NET MVC框架支持多种不同类型的过滤器:

  1. Authorization filters – 实现IAuthorizationFilter 特性.
  2. Action filters – 实现IActionFilter 特性.
  3. Result filters – 实现IResultFilter 特性.
  4. Exception filters –实现IExceptionFilter 特性.

Filters 按照上面列出的顺序执行。例如, authorization filters 总是在action filters之前执行,exception filters在所有其他类型的filter之后执行.

ActionFilterAttribute 基类

为了使你能够更加容易的实现自定义的action filter, ASP.NET MVC框架包含一个ActionFilterAttribute 基类. 这个类实现了IActionFilterIResultFilter 接口,并且继承了Filter 类。

ActionFilterAttribute 基类拥有以下可以重载的方法:

  • OnActionExecuting在action method调用前发生。
  • OnActionExecuted在action method调用后发生, 但是在result执行前发生 (在 view 呈现前)
  • OnResultExecuting在result执行前发生(在view 呈现前)
  • OnResultExecuted 在result执行后发生(在view 呈现后)

创建一个ASP.NET MVC OutputCache ActionFilterAttribute

使用ASP.NET MVC 框架, 简单的指定OutputCache 指令并不能达到理想的效果. 幸好, ActionFilterAttribute让你能够在 controller action执行的前后运行代码.

让我们使用类似的方法来创建OutputCache ActionFilterAttribute

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->[OutputCache(Duration=60,VaryByParam="*",CachePolicy=CachePolicy.Server)]
publicActionResultIndex()
{
//...
}

我们将使用命名为CachePolicy的枚举类型来指定OutputCache 特性应怎样以及在哪里进行缓存:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicenumCachePolicy
{
NoCache
=0,
Client
=1,
Server
=2,
ClientAndServer
=3
}

1.实现client-side缓存

事实上,这是很容易的。在view呈现前,我们将增加一些HTTP头到响应流。网页浏览器将获得这些头部,并且通过使用正确的缓存设置来回应请求。如果我们设置duration为60,浏览器将首页缓存一分钟。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->usingSystem.Web.Mvc;

namespaceMVCActionFilters.Web.Models
{
publicclassOutputCache:System.Web.Mvc.ActionFilterAttribute
{
publicintDuration{get;set;}
publicCachePolicyCachePolicy{get;set;}

publicoverridevoidOnActionExecuted(ActionExecutedContextfilterContext)
{
if(CachePolicy==CachePolicy.Client||CachePolicy==CachePolicy.ClientAndServer)
{
if(Duration<=0)return;

//用于设置特定于缓存的HTTP标头以及用于控制ASP.NET页输出缓存
HttpCachePolicyBasecache=filterContext.HttpContext.Response.Cache;
TimeSpancacheDuration
=TimeSpan.FromSeconds(Duration);

cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(DateTime.Now.Add(cacheDuration));
cache.SetMaxAge(cacheDuration);
cache.AppendCacheExtension(
"must-revalidate,proxy-revalidate");
}
}
}
}

2. 实现server-side缓存

Server-side 缓存有一点难度. 首要的,在输出缓存系统中,我们将不得不准备HTTP响应为可读的。为了这样做,我们首先保存当前的HTTP context到类的一个变量中. 然后, 我们创建一个新的httpcontext ,通过它将数据写入StringWriter,同时允许读操作可以发生:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->existingContext=System.Web.HttpContext.Current;//保存当前的HTTP context到类的一个变量中
writer
=newStringWriter();
HttpResponseresponse
=newHttpResponse(writer);
HttpContextcontext
=newHttpContext(existingContext.Request,response)
{
User
=existingContext.User
};
System.Web.HttpContext.Current
=context;

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicoverridevoidOnResultExecuting(ResultExecutingContextfilterContext)
{
if(CachePolicy==CachePolicy.Server||CachePolicy==CachePolicy.ClientAndServer)
{
//获取缓存实例
cache=filterContext.HttpContext.Cache;

//获取缓存数据
objectcachedData=cache.Get(GenerateKey(filterContext));
if(cachedData!=null)
{
//返回缓存数据
cacheHit=true;
filterContext.HttpContext.Response.Write(cachedData);
filterContext.Cancel
=true;
}
else
{
//重新设置缓存数据
existingContext=System.Web.HttpContext.Current;
writer
=newStringWriter();
HttpResponseresponse
=newHttpResponse(writer);
HttpContextcontext
=newHttpContext(existingContext.Request,response)
{
User
=existingContext.User
};
foreach(varkeyinexistingContext.Items.Keys)
{
context.Items[key]
=existingContext.Items[key];
}
System.Web.HttpContext.Current
=context;
}
}
}

利用该代码,我们能从高速缓存中检索现有项,并设置了HTTP响应能够被读取。在视图呈现之后,将数据存储在高速缓存中:

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->publicoverridevoidOnResultExecuted(ResultExecutedContextfilterContext)
{
//服务器端缓存?
if(CachePolicy==CachePolicy.Server||CachePolicy==CachePolicy.ClientAndServer)
{
if(!cacheHit)
{
//存储原有的context
System.Web.HttpContext.Current=existingContext;

//返回呈现的数据
existingContext.Response.Write(writer.ToString());

//增加数据到缓存
cache.Add(
GenerateKey(filterContext),
writer.ToString(),
null,
DateTime.Now.AddSeconds(Duration),
Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
null);
}
}
}

你现在注意到添加了一个VaryByParam到 OutputCache ActionFilterAttribute。当缓存server-side时,我可以通过传入的参数来改变缓存存储。这个GenerateKey方法会产生一个依赖于controller,action和VaryByParam的键。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->privatestringGenerateKey(ControllerContextfilterContext)
{
StringBuildercacheKey
=newStringBuilder();

//Controller+action
cacheKey.Append(filterContext.Controller.GetType().FullName);
if(filterContext.RouteData.Values.ContainsKey("action"))
{
cacheKey.Append(
"_");
cacheKey.Append(filterContext.RouteData.Values[
"action"].ToString());
}

//Variationbyparameters
List<string>varyByParam=VaryByParam.Split(';').ToList();

if(!string.IsNullOrEmpty(VaryByParam))
{
foreach(KeyValuePair<string,object>pairinfilterContext.RouteData.Values)
{
if(VaryByParam=="*"||varyByParam.Contains(pair.Key))
{
cacheKey.Append(
"_");
cacheKey.Append(pair.Key);
cacheKey.Append(
"=");
cacheKey.Append(pair.Value.ToString());
}
}
}
returncacheKey.ToString();
}

现在你可以增加OutputCache attribute到应用程序的任何一个controller 与controller action中。

<!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->[MVCActionFilters.Web.Common.OutputCache(Duration=20,VaryByParam="*",CachePolicy=Common.CachePolicy.Client)]
publicstringCache()
{
returnDateTime.Now.ToString();
}

设置CachePolicy为Common.CachePolicy.Client时,将直接在客户端缓存中读取数据。

总结

需注意事件的发生时间段

  • OnActionExecuting在action method调用前发生。
  • OnActionExecuted在action method调用后发生, 但是在result执行前发生 (在 view 呈现前)
  • OnResultExecuting在result执行前发生(在view 呈现前)
  • OnResultExecuted 在result执行后发生(在view 呈现后)
  • 分享到:
    评论

    相关推荐

      asp.net MVC4 CMS

      ASP.NET MVC4 CMS 是一个基于微软的ASP.NET MVC4框架构建的内容管理系统,它提供了一种高效、可扩展...通过深入研究其源代码,开发者可以学习到如何构建高效、可扩展的Web应用,并提升在ASP.NET MVC平台上的开发技能。

      ASP.NET MVC企业实战源代码Chapter12.rar

      通过本书的学习,读者可以全面掌握ASP.NET MVC的开发,并从代码中获取软件开发与架构设计的经验与灵感。本书具有很大的参考价值,既适合ASP.NET MVC开发初学者阅读,也适合有一定基础的ASP.NET MVC开发人员进行技术...

      ASP.NET MVC5

      学习ASP.NET MVC5,开发者可以掌握Web应用程序的高级开发技巧,包括如何组织项目结构、如何处理用户输入、如何进行数据库操作、如何实现用户认证和授权,以及如何调试和测试代码。"J.T.ASP.NET MVC 5.pdf"这个文件很...

      ASP.NET MVC学习笔记-Controller与View传值.

      ASP.NET MVC学习笔记-Controller与View传值.

      Asp.Net MVC案例教程

      Asp.Net MVC是一种基于模型-视图-控制器(Model-View-Controller)设计模式的Web应用程序开发框架。它由微软公司推出,旨在...通过学习这些案例,开发者可以逐步掌握Asp.Net MVC的精髓,从而高效地构建现代Web应用。

      ASP.NET MVC5 编程实战.pdf

      ASP.NET MVC5 是微软开发的一款用于构建Web应用程序的框架,它结合了模型-视图-控制器(MVC)设计模式、ASP.NET Web Forms组件以及Web API功能,为开发者提供了更灵活、可测试的Web开发解决方案。这本书《ASP.NET ...

      asp.net mvc 示例项目

      在这个"asp.net mvc 示例项目"中,我们可以深入学习和理解ASP.NET MVC的核心概念和实践技巧。 首先,我们来探讨一下ASP.NET MVC的核心组成部分: 1. **模型(Model)**:模型是应用程序中的业务逻辑和数据处理部分...

      ASP.NET MVC学习资料

      过去的几年里,很多人要求ASP.NET的一件事情就 是对使用基于model-view-controller(模型-视 图-控制器,简称MVC)架构来开发web应用的内置 支持。。

      基于ASP.NET MVC项目实例

      为了理解这个基于ASP.NET MVC的项目,你可以按照以下步骤进行学习: - **了解基本概念**:首先,你需要熟悉MVC模式的基本原理,以及ASP.NET MVC框架的关键组件。 - **安装环境**:确保你已安装了Visual Studio,并...

      ASP.NET MVC项目实例

      ASP.NET MVC作为微软官方的.NET平台下MVC解决方案,自诞生起就吸引了众多.NET平台开发人员的眼球。ASP.NET MVC从一开始的设计思路就与Struts不同,它的映射是利用路由配置而非xml,从而大大降低了开发复杂度,并且比...

      ASP.NET MVC4

      ASP.NET MVC4是一个基于模型-视图-控制器(Model-View-Controller)设计模式的开源Web应用程序框架,由...通过阅读提供的"ASP.NET MVC4 教程.pdf",你可以系统地学习这一框架,并逐步成为ASP.NET MVC4的熟练开发者。

      ASP.NET MVC4 Web编程

      学习ASP.NET MVC4 Web编程,你需要掌握C#语言、.NET Framework基础、HTML、CSS和JavaScript等前端技术,以及MVC设计模式的理解。通过阅读“ASP.NET MVC4 Web编程(jb51.net).pdf”这样的资源,你可以深入理解这些概念...

      ASP.NET MVC 5 网站开发之美

      在这个标题为“ASP.NET MVC 5 网站开发之美”的资源中,我们可以期待深入学习如何利用这个框架创建高质量的Web应用。 1. **MVC设计模式**:MVC模式是软件工程中的一种设计模式,它将应用程序分为三个主要部分:模型...

      dwz框架 asp.net mvc3

      通过分析这个项目,开发者可以学习如何将DWZ的组件与ASP.NET MVC3的路由、动作方法、视图等元素结合起来,实现功能完善的Web应用。 总之,DWZ框架与ASP.NET MVC3的结合,为开发人员提供了一种高效的Web开发解决方案...

      【全网首发】ASP.NET MVC4开发指南(附带源码)

      这个"ASP.NET MVC4开发指南"提供了一套全面的学习资源,旨在帮助开发者掌握这一强大的Web开发技术。 MVC(Model-View-Controller)模式是ASP.NET MVC4的核心设计原则,它将应用程序分为三个主要部分:模型(Model)...

      基于ASP.NET MVC 2 的小程序

      通过学习和实践这个基于ASP.NET MVC 2 的小程序,你将能够掌握MVC设计模式,以及如何利用该框架构建功能完善的网站。记得要深入研究每个组件,理解它们的作用以及如何协同工作,这样你才能充分利用ASP.NET MVC 2 的...

      ASP.NET MVC 5入门指南(中文PDF+源码)

      ASP.NET MVC 5入门指南 (中文PDF+源碼) 1. ASP.NET MVC 5 - 开始MVC 5之旅 2. ASP.NET MVC 5 - 控制器 3. ASP.NET MVC 5 - 视图 4. ASP.NET MVC 5 - 将数据从控制器传递给视图 5. ASP.NET MVC 5 - 添加一个模型 6. ...

      Pro ASP.NET MVC 5 Platform(Apress,Adam.Freeman,2014)

      The power of ASP.NET MVC 5 stems from the underlying ASP.NET platform. To make your ASP.NET MVC applications the best they can be, you need to fully understand the platform features and know how they ...

      Asp.net Mvc官方源代码

      通过研究ASP.NET MVC的官方源代码,开发者不仅可以深入了解MVC模式的实现细节,还能学习到最佳实践,提升Web应用的开发效率和质量。源代码的阅读和学习对于深入理解Web开发的底层机制至关重要,尤其是对于那些希望...

      ASP.NET MVC 4高级编程(第4版)清晰完整PDF版

      MVC专家“梦之队”对ASP.NET MVC 4的全新诠释 由Microsoft专家和极受敬重的软件开发社区负责人撰写的《ASP.NET MVC 4高级编程(第4版)》将带您学习最前沿的Web框架:ASP.NET MVC 4。本书开篇简要介绍ASP.NET MVC框架...

    Global site tag (gtag.js) - Google Analytics