http://www.hemelock.com

云顶网站

时间:2020-01-04

图片 1

MVC过滤器详解

 

APS.NET MVC中(以下简称“MVC”)的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理。这时候就用到了过滤器。

  MVC支持的过滤器类型有四种,分别是:Authorization(授权),Action(行为),Result(结果)和Exception(异常)。如下表,

过滤器类型

接口

描述

Authorization

IAuthorizationFilter

此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

Exception

IExceptionFilter

用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

Action

IActionFilter

用于进入行为之前或之后的处理

Result

IResultFilter

用于返回结果的之前或之后的处理

  但是默认实现它们的过滤器只有三种,分别是Authorize(授权),ActionFilter,HandleError(错误处理);各种信息如下表所示

过滤器

类名

实现接口

描述

ActionFilter

AuthorizeAttribute

IAuthorizationFilter

此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

HandleError

HandleErrorAttribute

IExceptionFilter

用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

自定义

ActionFilterAttribute

IActionFilter和IResultFilter

用于进入行为之前或之后的处理或返回结果的之前或之后的处理

  下面介绍的过滤器中,除了上面这几种外,还多加一种过滤器OutputCache

 

1           授权过滤器Authorize

 

1.1          默认Authorize使用

  现在在网上无论是要求身份验证的地方多得是,发邮件,买东西,有时候就算吐个槽都要提示登录的。这里的某些操作,就是要经过验证授权才被允许。在MVC中可以利用Authorize来实现。例如一个简单的修改密码操作

        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }

它需要用户通过了授权才能进入到这个行为方法里面,否则硬去请求那个页面的话,只会得到这个结果

图片 2

如果要通过验证,通过调用FormsAuthentication.SetAuthCookie方法来获得授权,登陆的页面如下

@model FilterTest.Models.LogInModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Login</title>
</head>
<body>
    <div>
    @using( Html.BeginForm()){
       <div>
        ID:@Html.TextBoxFor(m=>m.UserName)
        <br />
        Password:@Html.PasswordFor(m => m.Password)
        <br />
        <input type="submit" value="login" />
       </div>
    }
    </div>
</body>
</html>

行为方法如下

        [HttpPost]//这里用了谓词过滤器,只处理POST的请求
        public ActionResult Login(LogInModel login)
        {
            if (login.UserName == "admin" && login.Password == "123456")
            {
                FormsAuthentication.SetAuthCookie(login.UserName, false);
                return Redirect("/Customer/ChangePassword");
            }

            return View();
        }

 

当然有登录也要有注销,因为注销是在登陆之后发生的,没登陆成功也就没有注销,所以注销的行为方法也要加上Authorize过滤器,注销调用的是FormsAuthentication.SignOut方法,代码如下

        [Authorize]
        public ActionResult LogOut()
        {
            FormsAuthentication.SignOut();
            return Redirect("/Customer/Login");
        }

1.2          自定义授权

我们不一定要用MVC默认的Authorize授权验证规则,规则可以自己来定,自定义授权过滤器可以继承AuthorizeAttribute这个类,这个类里面有两个方法是要重写的

  •          bool AuthorizeCore(HttpContextBase httpContext):这里主要是授权验证的逻辑处理,返回true的则是通过授权,返回了false则不是。
  •          void HandleUnauthorizedRequest(AuthorizationContext filterContext):这个方法是处理授权失败的事情。

这里就定义了一个比较骑呢的授权处理器,当请求的时候刚好是偶数分钟的,就通过可以获得授权,反之则不通过。当授权失败的时候,就会跳转到登陆页面了。

 

    public class MyAuthorizeAttribute:AuthorizeAttribute
    {

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            //return base.AuthorizeCore(httpContext);
            return DateTime.Now.Minute % 2 == 0
        }


        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.HttpContext.Response.Redirect("/Customer/Login");

            //base.HandleUnauthorizedRequest(filterContext);
        }
    }

 

然后用到一个行为方法上,

        [MyAuthorize]
        public ActionResult ShowDetail()
        {
            return View();
        }

每当偶数分钟的时候就可以访问得到这个ShowDetail的视图,否则就会跳到了登陆页面了。

 

2           处理错误过滤器HandleError

 

2.1          默认HandleError使用

在往常的开发中,想到异常处理的马上就会想到try/catch/finally语句块。在MVC里面,万一在行为方法里面抛出了什么异常的,而那个行为方法或者控制器有用上HandleError过滤器的,异常的信息都会在某一个视图显示出来,这个显示异常信息的视图默认是在Views/Shared/Error

这个HandleError的属性如下

属性名称

类型

描述

ExceptionType

Type

要处理的异常的类型,相当于Try/Catch语句块里Catch捕捉的类型,如果这里不填的话则表明处理所有异常

View

String

指定需要展示异常信息的视图,只需要视图名称就可以了,这个视图文件要放在Views/Shared文件夹里面

Master

String

指定要使用的母版视图的名称

Order

Int

指定过滤器被应用的顺序,默认是-1,而且优先级最高的是-1

这个Order属性其实不只这个HandleError过滤器有,其优先级规则跟其他过滤器的都是一样。

下面则故意弄一个会抛异常的行为方法

        [HandleError(ExceptionType = typeof(Exception))]
        public ActionResult ThrowErrorLogin()
        {
            throw new Exception("this is ThrowErrorLogin Action Throw");
        }

 

光是这样还不够,还要到web.config文件中的<system.web>一节中添加以下代码

<customErrors mode="On" />

 

因为默认的开发模式中它是关闭的,要等到部署到服务器上面才会开启,让异常信息比较友好的用一个视图展现。

  像这里访问ThrowErrorLogin视图时,由于抛出了一次,就转到了一个特定的视图

图片 3

  在这里看到的异常视图是这样的,除了用这个建项目时默认生成的异常视图之外,我们还可以自己定义异常视图,视图里面要用到的异常信息,可以通过@Model获取,它是一个ExceptionInfo类型的实例,例如这里建了一个异常视图如下

 

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>MyErrorPage</title>
</head>
<body>
    <div>
    <p>
        There was a <b>@Model.Exception.GetType().Name</b> 
        while rendering <b>@Model.ControllerName</b>'s 
        <b>@Model.ActionName</b> action. 
    </p> 
    <p style="color:Red"> 
        <b>@Model.Exception.Message</b> 
    </p> 
    <p>Stack trace:</p> 
    <pre style="  padding: 0px; color: rgb(0, 0, 255); line-height: 1.5 !important;">>@Model.Exception.StackTrace</pre>
        </div>
</body>
</html>

 

  它存放的路径是~/Views/Shared里面,像上面的行为方法如果要用异常信息渲染到这个视图上面,在控制器的处改成这样就可以了

[HandleError(ExceptionType = typeof(Exception), View = "MyErrorPage")]

 

图片 4

2.2          自定义错误异常处理

  这里的错误处理过滤器也可以自己来定义,做法是继承HandleErrorAttribute类,重写void OnException(ExceptionContext filterContext)方法,这个方法调用是为了处理未处理的异常,例如

 

        public override void OnException(ExceptionContext filterContext)
        {
            //base.OnException(filterContext);
            if (!filterContext.ExceptionHandled && 
                filterContext.Exception.Message == "this is ThrowErrorLogin Action Throw")
            { 
                filterContext.ExceptionHandled=true;
                filterContext.HttpContext.Response.Write("5洗ten No Problem<br/>" +
                    filterContext.Exception.ToString());
            }
        }

 

  这里用到的传入了一个ExceptionContext的对象,既可以从它那里获得请求的信息,又可以获取异常的信息,它部分属性如下

属性名称 类型 描述
ActionDescriptor ActionDescriptor 提供详细的操作方法
Result ActionResult 结果的操作方法,过滤器可以取消,要求将此属性设置为一个非空值
Exception Exception 未处理的异常
ExceptionHandled bool 另一个过滤器,则返回true,如果有明显的异常处理

   这里的ExceptionHandler属性要提一下的是,如果这个异常处理完的话,就把它设为true,那么即使有其他的错误处理器捕获到这个异常,也可以通过ExceptionHandler属性判断这个异常是否经过了处理,以免重复处理一个异常错误而引发新的问题。

3           OutputCache过滤器

  OutputCache过滤器用作缓存,节省用户访问应用程序的时间和资源,以提高用户体验,可这个我试验试不出它的效果。留作笔记记录一下。OutputCacheAttribute这个类有以下属性

 

属性名称

类型

描述

Duration

int

缓存的时间,以秒为单位,理论上缓存时间可以很长,但实际上当系统资源紧张时,缓存空间还是会被系统收回。

VaryByParam

string

以哪个字段为标识来缓存数据,比如当“ID”字段变化时,需要改变缓存(仍可保留原来的缓存),那么应该设VaryByParam为"ID"。这里你可以设置以下几个值:
* = 任何参数变化时,都改变缓存。
none = 不改变缓存。
以分号“;”为间隔的字段名列表 = 列表中的字段发生变化,则改变缓存。

Location

OutputCacheLocation

缓存数据放在何处。默认是Any,其他值分别是Client,Downstream,Server,None,ServerAndClient

NoStore

bool

用于决定是否阻止敏感信息的二级存储。

  例如一个OutputCache过滤器可以这样使用

        [OutputCache(Location= System.Web.UI.OutputCacheLocation.Client,Duration=60)]
        public ActionResult Login()
        {
            return View();
        }

 

  或者有另外一种使用方式——使用配置文件,在<system.web>节点下添加以下设置

 

    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="testCache" location="Client" duration="60"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

 

使用控制的时候就这样

        [OutputCache(CacheProfile="testCache")]
        public ActionResult Login()
        {
            return View();
        }

4           自定义过滤器

  万一前面介绍的过滤器也满足不了需求,要在行为方法执行返回的前前后后定义自己的处理逻辑的话,这个自定义过滤器就应该能派上用场了。若要自定义一个过滤器,则要继承ActionFilterAttribute类,这个类是一个抽象类,实现了IActionFilter和IResultFilter接口,主要通过重写四个虚方法来达到在行为方法执行和返回的前后注入逻辑

方法

参数

描述

OnActionExecuting

ActionExecutingContext

在行为方法执行前执行

OnActionExecuted

ActionExecutedContext

在行为方法执行后执行

OnResultExecuting

ResultExecutingContext

在行为方法返回前执行

OnResultExecuted

ResultExecutedContext

在行为方法返回后执行

  四个方法执行顺序是OnActionExecuting——>OnActionExecuted——>OnResultExecuting——>OnResultExecuted。上面四个方法的参数都是继承基ContollorContext类。例如下面定义了一个自定义的过滤器

 

   public class MyCustomerFilterAttribute : ActionFilterAttribute
    {
        public string Message { get; set; }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            filterContext.HttpContext.Response.Write(string.Format( "<br/> {0} Action finish Execute.....",Message));
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            CheckMessage(filterContext);
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action start Execute.....", Message));
            base.OnActionExecuting(filterContext);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action finish Result.....", Message));
            base.OnResultExecuted(filterContext);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write(string.Format("<br/> {0} Action start Execute.....", Message));
            base.OnResultExecuting(filterContext);
        }

        private void CheckMessage(ActionExecutingContext filterContext)
        { 
            if(string.IsNullOrEmpty( Message)||string.IsNullOrWhiteSpace(Message))
                Message = filterContext.Controller.GetType().Name + "'s " + filterContext.ActionDescriptor.ActionName;
        }
    }

 

 

使用它的行为方法定义如下

        [MyCustomerFilter]
        public ActionResult CustomerFilterTest()
        {
            Response.Write("<br/>Invking CustomerFilterTest Action");
            return View();
        }

 

执行结果如下

图片 5

这个就证明了上面说的顺序。

当控制器也使用上这过滤器时,而行为方法不使用时,结果如下

图片 6

如果控制器和行为方法都使用了过滤器,理论上是显示上面两个结果的有机结合。但实际不然,因为在定义过滤器的时候还少了一个特性:[AttributeUsage(AttributeTargets.All, AllowMultiple = true)],把这个加在MyCustomerFilterAttribute就行了。

    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]//多次调用
    public class MyCustomerFilterAttribute : ActionFilterAttribute
    {
        ……
    }

 

图片 7

  由这幅图可以看出,同一个过滤器分别用在了控制器和行为方法中,执行同一个方法时都会有先后顺序,如果按默认值(不设Order的情况下),一般的顺序是由最外层到最里层,就是“全局”——>“控制器”——>“行为方法”;而特别的就是错误处理的过滤器,由于异常是由里往外抛的,所以它的顺序刚好也反过来:“行为方法”——>“控制器”——>“全局”。

  既然这里有提到全局的过滤器,那么全局的过滤器是在Global.asax文件里面的RegisterGlobalFilters(GlobalFilterCollection filters)中设置的

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new MyFilters.MyCustomerFilterAttribute() { Message="Global"});//全局过滤器
        }

 

这里它默认也添加了一个错误处理的过滤器来处理整个MVC应用程序所抛出的异常。

2.3.4、指定默认参数值

如果希望处理不含动作方法参数的请求,但又不想在代码中检查null值或抛出异常,可以使用C#的可选参数特性来代替。如下所示:

 

1  public ActionResult List(string query = "all", int page = 1)
2         {
3             //此处省略代码N行...
4             return View();
5         }

 

在定义参数时,通过对参数赋值的办法,可以将参数标记为可选的,如上诉代码中,给query和page参数提供了默认值。MVC框架会试图通过请求为这些参数获取值,但如果没有值可用,那么将用所指定的默认值代替。

对于string类型参数query,注意string类型是引用类型,这意味着不需要检查null值。如果请求为指定查询字符串,那么该动作(Action)方法将以字符串“all”进行调用。对于int类型参数,注意int类型是值类型,在没有page值时,请求不会导致错误,该方法将以默认值“1”进行调用。

 

app.js

3、控制器
控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后用确定用哪个视图来显示模型处理返回的数据。

2.3.3、理解可选参数与必须的参数

如果MVC框架找不到引用类型参数(如:string或object)的值,动作方法仍然会被调用,但对该参数会使用一个null值,若找不到值类型参数(如:int或double)的值则会抛出一个异常,并且不会调用动作方法。

a、值类型参数是必须被赋值的。如果想让此参数和引用类型参数一样,可以定义成int?如:public ActionResult Index(int? num),当依然没有值时,不会发生异常,而是会传递null值。

b、引用类型的参数是可选的。为了使它成为必须的(保证一个非空的值被传递),在动作(Action)方法上添加一些代码拒绝null。例如,在该值等于null时,抛出一个ArgumentNullException异常。

 

  1. Ext.onReady(function(){
  2. Ext.QuickTips.init();
  3. Ext.Loader.setConfig({ //开启自动加载功能
  4. enabled:true
  5. });
  6. Ext.application({
  7. name:'AM', //自定义命名空间,通常都定义为AM
  8. appFolder:'app', //配置Ext框架所在的文件目录
  9. launch:function(){ //在所有资源都载入成功后运行
  10. Ext.create('Ext.container.Viewport',{
  11. items:{
  12. width:1500,
  13. height:500,
  14. xtype:'mainlayout' //这里引用了自定义的组件mainlayout(视图层的MainLayout的别称)
  15. }
  16. });
  17. },
  18. controllers:[ //加载所有的控制器
  19. 'UserController'
  20. ]
  21. });
  22. }); 控制层:

    UserController.js

    [javascript] view plaincopyprint?

    1. Ext.define('AM.controller.UserController',{
    2. extend:'Ext.app.Controller',//继承Ext.app.Controller类
    3. init:function(){
    4. this.control({ //控制事件处理
    5. 'userlist button[id=add]':{
    6. click:function(){
    7. //do something
    8. }
    9. }
    10. });
    11. },
    12. views:[
    13. 'UserList', //放在MainLayout之前加载
    14. 'DeptList',
    15. 'MainLayout'
    16. ],
    17. stores:[
    18. 'UserStore',
    19. 'DeptStore'
    20. ],
    21. models:[
    22. 'UserModel'
    23. ]
    24. });

      Model层:

      UserModel.js

      [javascript] view plaincopyprint?

      1. Ext.define('AM.model.UserModel',{
      2. extend:'Ext.data.Model', //用来绑定到grid表字段
      3. fields:[
      4. {name:'id',type:'string'},
      5. {name:'name',type:'auto'},
      6. {name:'password',type:'string'},
      7. {name:'birth',type:'auto'},
      8. {name:'email',type:'auto'},
      9. {name:'intro',type:'string'}
      10. ]
      11. });

        Store层:

        UserStore.js

        [javascript] view plaincopyprint?

        1. Ext.define('AM.store.UserStore',{
        2. extend:'Ext.data.Store',
        3. model:'AM.model.UserModel',
        4. proxy:{
        5. type:'ajax',
        6. url:'/ExtjsTest/test/readuser',
        7. reader:{
        8. type:'json',
        9. root:'userinfo'
        10. },
        11. writer:{
        12. type:'json'
        13. }
        14. },
        15. autoLoad:true
        16. }); DeptStore.js [javascript] view plaincopyprint?

          1. Ext.define('AM.store.DeptStore',{
          2. extend:'Ext.data.TreeStore',
          3. defautRootId:'root',
          4. proxy:{
          5. type:'ajax',
          6. url:'/ExtjsTest/test/showuser',
          7. reader:{
          8. type:'json'
          9. },
          10. writer:{
          11. type:'json'
          12. }
          13. },
          14. autoLoad:true
          15. }); 视图层:

            UserList.js

            [javascript] view plaincopyprint?

            1. Ext.define('AM.view.UserList',{
            2. extend:'Ext.grid.Panel', //GridPanel组件
            3. alias:'widget.userlist', //别名
            4. // title:'用户信息',
            5. width:500,
            6. height:500,
            7. store:'UserStore', //绑定UserStore数据集
            8. selModel:{
            9. selType:'checkboxmodel'
            10. },
            11. tbar:[{text:"添加",id:'add'},{text:'删除',id:'del'},{text:'保存',id:'save'}], //按钮事件在控制层写
            12. columns:[{header:'编号',dataIndex:'id',field:{xtype:'textfield',allowBlank:false}},
            13. {header:'姓名',dataIndex:'name',field:{xtype:'textfield',allowBlank:false}},
            14. {header:'密码',dataIndex:'password',field:{xtype:'textfield',allowBlank:false}},
            15. {header:'生日',dataIndex:'birth',field:{xtype:'datefield',allowBlank:false}},
            16. {header:'邮件',dataIndex:'email',field:{xtype:'textfield',allowBlank:false}},
            17. {header:'简介',dataIndex:'intro',field:{xtype:'textfield',allowBlank:false}}],
            18. ]
            19. }); DeptList.js [javascript] view plaincopyprint?

              1. 1. Ext.define('AM.view.DeptList',{ 2. extend:'Ext.tree.Panel', //TreePanel组件 3. alias:'widget.deptlist', 4. // title:'树', 5. width:300, 6. height:500, 7. rootVisible:false, 8. dockedItems:[{ 9. xtype:'toolbar', 10. dock:'left', 11. items:[ 12. {xtype:'button',text:'add',id:'add'}, 13. {xtype:'button',text:'delete',id:'del'}, 14. {xtype:'button',text:'copy',id:'copy'} 15. ] 16. }, 17. store:'DeptStore', //绑定DeptStore数据集 18. } 19. }); 效果图: 图片 8

二、为什么要使用 MVC

2.1、数据来源

a、查询字符串值 b、表单数据 c、路由数据

控制器需要经常访问来自输入请求的数据,如查询字符串表单数据、以及由路由系统根据输入的URL解析得到的参数的值。访问这些数据有三种主要方式。

(1)、从上下文对象提取。

(2)、作为参数被传递给动作方法(Action Method)而形成的数据。

(3)、明确调用框架的模型绑定(Model Binding)功能。

注意:参数名称是忽略大小写的,如Request["Test"]与Request["test"]结果是一样的。如下图:

View部分

 

Controller部分

 

 

                        http://www.bkjia.com/Javascript/821932.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/821932.htmlTechArticleapp.js [javascript]
                        view plaincopyprint? Ext.onReady(function(){
                        Ext.QuickTips.init(); Ext.Loader.setConfig({
                        //开启自动加载功能 enabled:true });
                        Ext.application({ name:'AM...

四、MVC是一条创建软件的好途径
MVC设计模式是一个很好创建软件的途径,它所提倡的一些原则,像内容和显示互相分离可能比较好理解。但是如果你要隔离模型、视图和控制器的构件,你可能需要重新思考你的应用程序,尤其是应用程序的构架方面。如果你肯接受MVC,并且有能力应付它所带来的额外的工作和复杂性,MVC将会使你的软件在健壮性,代码重用和结构方面上一个新的台阶。

目录

[javascript] view plaincopyprint?

现在我们总结MVC的处理过程,首先控制器接收用户的请求,并决定应该调用哪个模型来进行处理,然后模型用业务逻辑来处理用户的请求并返回数据,最后控制器用相应的视图格式化模型返回的数据,并通过表示层呈现给用户。

3.1、理解动作结果(Action Result)

原理:

a、MVC框架接收从Action方法返回的ActionResult对象,并调用定义在ActionResult类里面ExecuteResult方法,对ActionResult进行实现,为我们处理Response对象并生成相关的输出。

b、MVC框架内置了许多ActionResult类型,都是从ActionResult类派生的,能够方便我们在Action方法里面选择具体的返回类型,比如要呈现到View,可以选择ViewResult作为Action方法的返回值。

MVC框架含有许多内置的动作结果类型如下图所示,所有这些类型都是派生于ActionResult,其中在Controller类中有便利的辅助器方法。下面将解释如何使用这些结果类型。

MVC框架支持的输出类型有: 1.视图 2.文本数据 3.XML数据 4.JSON数据 5.文件或者二进制数据 6.返回错误和HTTP Codes 7.定制的ActionResult 8.重定向

 

 

对我来说,控制器的也提供了一个好处,就是可以使用控制器来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择模型进行处理,然后选择视图将处理结果显示给用户。

3.5、返回文本数据

MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。

 

因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变你的应用程序的数据层和业务规则。如果你想把你的数据库从MySQL移植到Oracle,或者改变你的基于RDBMS数据源到LDAP,只需改变你的模型即可。一旦你正确的实现了模型,不管你的数据来自数据库或是LDAP服务器,视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互对立,改变其中一个不会影响其它两个,所以依据这种设计思想你能构造良好的松偶合的构件。

2.1、数据来源

大部分Web应用程序都是用像ASP,PHP,或者CFML这样的过程化语言来创建的。它们将像数据库查询语句这样的数据层代码和像HTML这样的表示层代码混在一起。经验比较丰富的开发者会将数据从表示层分离开来,但这通常不是很容易做到的,它需要精心的计划和不断的尝试。MVC从根本上强制性的将它们分开。尽管构造MVC应用程序需要一些额外的工作,但是它给我们带来的好处是无庸质疑的。

2.3、使用动作(Action)方法参数

你将不得不花费相当可观的时间去考虑如何将MVC运用到你的应用程序,同时由于模型和视图要严格的分离,这样也给调试应用程序到来了一定的困难。每个构件在使用之前都需要经过彻底的测试。一旦你的构件经过了测试,你就可以毫无顾忌的重用它们了。

2.2、通过上下文对象获取数据

根据我个人经验,由于我们将一个应用程序分成了三个部件,所以使用MVC同时也意味着你将要管理比以前更多的文件,这一点是显而易见的。这样好像我们的工作量增加了,但是请记住这比起它所能带给我们的好处是不值一提。

3.4.4、使用TempData保留重定向数据

 重定向会引起浏览器提交整个新的HTTP请求,这意味着无法访问原始的请求的细节。如果想将数据从一个请求传递到下一个请求,可以使用TempData()方法。

TempData类似于Session,不同的是TempData在被读取以后会被标记删除,并且当请求被处理的时候被移除。这是一个针对想在整个重定向过程中保持短期数据的非常完美的安排。如下示例:

首先添加一个MySecond控制器,并添加对应的视图,视图引擎为Razor并编写如下代码:

 MySecond控制器代码

 

 1  public class MySecondController : Controller
 2     {
 3         public ActionResult Index()
 4         {
 5             TempData["Message"] = "Hello TempData";
 6             TempData["Data"] = "TempData的值只能读取一次";
 7             return View();
 8         }
 9         public ActionResult TempDataTest()
10         {
11             return View();
12         }
13     }
14     

 

Index视图代码

 

 1 @{
 2     Layout = null;
 3 }
 4 
 5 <!DOCTYPE html>
 6 
 7 <html>
 8 <head>
 9     <meta name="viewport" content="width=device-width" />
10     <title>Index</title>
11 </head>
12 <body>
13     <div>
14         the Data is:@TempData["Data"]
15     </div>
16 </body>
17 </html>

 

TempDataTest视图代码

 

 1 @{
 2     Layout = null;
 3 }
 4 
 5 <!DOCTYPE html>
 6 
 7 <html>
 8 <head>
 9     <meta name="viewport" content="width=device-width" />
10     <title>TempDataTest</title>
11 </head>
12 <body>
13     <div>
14         the Data is:@TempData["Data"]<br/>
15         the Message is:@TempData["Message"]
16     </div>
17 </body>
18 </html>

 

运行结果如下:

 

 

注意:在Index里面没有读取TempData["Message"]的值,但是Index和TempDataTest都读取了TempData["Data"]的值。这样做是为了验证TempData里面的值在不同的视图只能读取一次。

TempData里面的值在一次请求里面只能读取一次。 如果我们想读取TempData的值但是又不让它被删除,可以使用TempData.Peek(“Data”)方法。 如果想在保持一次TempData里面的值,可以使用TempData.Keep("Data")。

 

2、模型
模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。例如它可能用象EJBs和ColdFusion Components这样的构件对象来处理数据库。被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

3.9、返回错误和HTTP Codes 

一、MVC如何工作

3.4.2、重定向到路由系统的URL

使用重定向到文本URL的缺点是:限定了URL,当路由发生改变后,必须更新URL。幸好我们可以使用路由系统,用RedirectToRoute方法来生成有效的URL该方法会创建 RedirectToRouteResult的一个实例。如下所示:

 

 

如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。

3.4、执行重定向

有一种动作(Action)方法的通常结果并不是直接产生输出,而是把用户的浏览器重定向导另一个URL。大多数情况下,这个URL是应用程序的另一个动作(Action)方法,用来生成你希望用户看到的输出。

重定向的Action方法不产生任何的输出,只是让浏览器重新请求一个其它的URL。在MVC程序中,一般会定向到其它的Action方法来产生输出。

在执行重定向时,发送了两个HTTP代码中的一个到浏览器。

(1)、发送HTTP 302状态编码,代表暂时重定向。(常用类型)

(2)、发送HTTP 301状态编码,表示永久重定向。(使用需谨慎)

重定向的类型有:1.重定向到文本URL   2.重定向到路由系统的URL  3.重定向到动作(Action)方法