MVC 读书笔记

一、路由

  1、HttpApplication中的ASP.NET MVC

  .Net 3.5 引入了System.Web.Routing程序集,通过Url Routing的机制,可以实现将一个虚拟路径的请求映射到一个Action方法上。

  在Asp.net MVC中,Route类指定Asp.net应用程序中针对虚拟路径请求的处理方式,可以为每种URL模式创建一个Route对象。Route类定义如下:

public class Route : RouteBase

  为了完成针对请求的路由工作,在Asp.net MVC中引入了称为路由表的数据结构来定义各种URL到实际处理程序之间的映射。在Asp.net MVC中,这个路由表的类型为RouteTable。RouteTable的Routes是一个static类型的属性,它的类型是RouteCollection,从类的命名就可以看出,这是一个强类型的Route对象集合,用来表示应用程序中所有的路由。

public class RouteTable
{
    public static RouteCollection Routes { get; }
}

  为了在HttpApplication的处理管道中将普通的请求处理转换到MVC的处理中,为了将URL映射到MVC的处理程序中,UrlRoutingModule注册了HttpApplication的如下两个事件,使得请求进入Asp.net MVC的处理中。

  • PostResolveRequestCache事件  
  • PostMapRequestHandler事件

  2、创建RouteTable

  一个网站应用程序只会有一个路由表,针对请求的路由表必须在请求真正被处理之前提前创建,默认情况下,创建路由表的工作将在Global.asax.cs文件中的Application_Start中完成。

  Asp.net MVC 3中的默认Global.asax.cs:

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }

  应用程序使用的路由表由RouteTable表示。RouteTable的Routes属性表示了路由对象的集合。

  路由表使用RouteTable表示,RouteTable的Routes属性表示了路由对象的集合。在上边的Global.asax.cs文件中,我们在应用程序首次处理请求之前未路由表增加了两个路由对象。

  在路由表内部通过路由对象来表示URL到Handler的映射。在上面的代码中,我们创建了两个路由对象。

  • 第一个路由,这是一个用于忽略特殊请求的路由,这个路由忽略所有扩展名为.axd的请求,这些请求将被按照经典的方式进行处理。这样,经典的一些特殊醒醒的请求,如Trace.axd,WebResource.axd等将被路由忽略,还会按照经典的方式进行处理。
  • 第二个路由,映射任何符合{controller}/{action}/{id}模式的UTL到MvcRouteHandler。其中第二个路由还提供了一个默认的参数。

  一般来说,对于ASP.NET MVC网站程序,一般不会请求有着.aspx扩展名的地址,而会请求一个有意义的虚拟地址,ASP.NET MVC通过路由表,将这个请求转发到一个叫做控制器的类上,控制器负责生成内容并把它发回浏览器。

  3、在IIS 6.0和IIS 7中的配置

  • 在IIS 6.0中,需要通过请求的扩展名将不同的请求映射到不同的应用程序扩展中,例如,对于经典的ASP.NET网站,我们需要将.aspx扩展名映射到aspnet_isapi.dll中。这个映射在我们安装.Net的时候,就已经由安装程序设置到IIS的应用程序配置中了。对于我们刚刚创建的有意义的URL来说,地址中根本没有扩展名,对于这些特殊的请求,我们可以通过通配符应用程序映射将所有的请求都映射到.Net网站应用程序中来。
  • 在IIS 7中,网站应用程序被分为两种类型运行模式:经典模式和集成模式。在应用程序池配置界面中可以对运行模式进行调整的。在集成模式下,.Net网站可以参与到IIS处理过程中,对于MVC项目来说,不需要进行文件扩展名的映射配置,就可以将请求传递到.Net网站应用程序中。IIS7中默认使用的是集成管线模式,默认情况下经典模式也被支持,所以就有两套扩展名与处理程序的映射配置:一套用于经典模式,一套用于集成模式。

  4、从URL到Route

  在ASP.NET MVC中,从URL到RouteData的映射通过Route对象表示,需要首先在RouteTable中注册Route信息,RouteTable中保存了当前应用程序的路由信息。具体来说,RouteTable的静态属性Routes包含了当前应用程序用于从URL映射到处理请求的所有路由信息。添加到路由表中的路由顺序非常重要,应用程序将会从前往后地在路由表中查找匹配当前请求的路由对象,所以,短的、特殊的路由应该加入到路由表的前方,一般化的路由应该在后面加入。当应用程序启动的时候,我们需要将所有的映射添加到路由表中,这个工作一般在Global.asax中进行。

  所有的Route必须派生自基类RouteBase,其定义如下:

public abstract class RouteBase
    {protected RouteBase();
        public abstract RouteData GetRouteData(HttpContextBase httpContext);
        public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    }

  每个路由对象必须能够通过GetRouteData获取对应的路由数据,而GetVirtualPath用来检测请求参数,查看当前的路由对象是否匹配这个请求。

  在Route中,实际的路由数据被以RouteData的类型保存。

    public class RouteData
    {
        public RouteData();
        public RouteData(RouteBase route, IRouteHandler routeHandler);
        public RouteValueDictionary DataTokens { get; }
        public RouteBase Route { get; set; }
        public IRouteHandler RouteHandler { get; set; }
        public RouteValueDictionary Values { get; }
        public string GetRequiredString(string valueName);
    }

  我们使用的Route派生自RouteBase,提供了多种不同的构造函数,使得我们可以以不同的方式来构建Route对象。

  1. URL请求参数的模板
  2. routeHandler这个请求的处理器对象
  3. 默认的处理参数

  另外,Constraints属性提供了约束URL的信息,用于限制URL的范围。

  通过RouteCollection的MapRoute扩展方法能够加入一个路由,这个方法提供了6个重载来方便我们添加路由。使用这种方式加入的路由将会使用一个默认的路由处理程序MvcRouteHandler来处理路由。

  不使用MapRoute,而是自定义一个Route对象,将会允许我们有更大的灵活性。

RouteTable.Routes.Add(
    new Route(
        "{controller}/{action}/{id}",
        new RouteValueDictionary(
            new{ Action = "Index", id = (string)null }),
    new ShowRouteHandler()
    )
);        

  在大型网站中,往往存在众多的Controller,从ASP.NET 2.0开始,提供了Area用来对大型网站的支持。Area用于对Controller进行逻辑分组,这个问题也同样通过Route进行了映射,这时候的URL如下所示:

  "AreaName/{controller}/{action}/{id}"

  在ASP.NET MVC中通过在Route中增加一个Area属性来解决这个问题,这个属性通过接口IRouteWithArea来指定。

namespace System.Web.Mvc{
  using Systen;

  public interface IRouteWithArea{
  string Atra{ get; }
  }
}

  不过也可以来自DataTokens中的area来表示Area名称。

  DataTokens["area"]

  含有Area的网站,默认生成了一个名为XXXXAreaRegistration.cs的代码文件,用于注册含有Area的URL映射。注册含有Area的路由如下所示,这个类派生自AreaRegistration,通过重写AreaName提供了当前Area的名字,这样,以后就可以通过这个名字来匹配Area,然后在这个Area中查询相应的控制器。

public class BlogAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get{ return "Blog"; }
    }
    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute("Blog_default","Blog/{controller}/{action}/{id}",new { action = "Index",id = UrlParameter.Optional })
    }
}

  在Global.asax中增加了注册含有Area的路由:

protected void Application_Start()
{
  //注意顺序不能颠倒
  //先定义了带有区域的路由
  AreaRegistration.RegisterAllAreas();
  //后注册没有区域的路由
  RegisterRoutes(RouteTable.Routes);
}

  我们也可以通过MapRoute提供一个默认值,当URL中没有提供这部分信息的时候,将使用默认值作为当前的值。

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

  如,当没有输入Controller将使用Home代替,Action=>Index,id=>""。

  5、Routing

  当PostMapRequestHandler事件触发的时候,ASP.NET已经完成了经典的获取处理程序的操作。但是,显然不可能通过传统方式获取ASP.NET MVC的处理程序,UrlRoutingModule将检查通过HttpContext对象的Items传递的路由对象,如果成功获取的话,那么,将通过路由对象的处理程序来重新设置当前的处理程序。

  对于ASP.NET MVC程序来说,将会创建一个实现IRouteHandler接口的对象,这个对象将被用来作为处理程序使用。不过,此时的处理程序并不像ASP.NET时代,直接完成处理请求,而是用于获取一个真正的处理程序,定义在命名空间Systen.Web.Routing下的接口IRouteHandler用于完成这个任务。

public interface IRouteHandler
{
    IHttpHandler GetHttpHandler(RequestContext requestContext);
}

  在ASP.NET MVC中,默认的处理对象如下:

public class MvcRouteHandler : IRouteHandler

  默认情况下,MvcRouteHandler将会创建一个MvcHandler对象开始处理过程。

public class MvcHandler : IHttpAsyncHandler,IHttpHandler,IRequiresSessionState

  如果在创建路由表的时候不使用MapRoute,而是通过创建Route对象的方法,那么,可以自行指定特定的路由处理程序。

  6、RequestContext的前世今生

  从ASP.NET 3.5SP1开始,在ASP.NET中定义了一组新的类型,以增强对于测试的支持。这组新的类型通过分别提供一个抽象的基类,使得我们可以简单的创建一个用于测试的派生类来完成测试工作。

  表示请求参数的基类HttpRequestBase定义了经典的HttpRequest同样的成员,但它现在是一个抽象类,允许我们继承

public abstract class HttpRequestBase

  在ASP.NET MVC使用的是它的派生类HttpRequestWrapper

public class HttpRequestWrapper : HttpRequestBase

  类似的其他对象如下表所示:

经典类型 MVC抽象基类 实现
HttpRequest HttpRequestBase HttpRequestWrapper
HttpResponse HttpResponseBase HttpResponseWrapper
HttpApplicationState HttpApplicationStateBase HttpApplicationStateWrapper
HttpServerUtility HttpServerUtilityBase HttpServerUtilityWrapper
HttpSessionState HttpSessionStateBase HttpSessionStateWrapper
HttpContext HttpContextBase HttpContextWrapper

  需要注意的是,在ASP.NET MVC中,经过Routing之后,相比经典的ASP.NET模式,增加了Routing信息,经典的HttpContext中没有Routing信息,RequestContext在HttpContext的基础上,增加了当前的Routing数据。

public class RequestContext
{
    public HttpContextBase HttpContext{ get; internal set;}
    public RouteData RouteData { get; internal set; }
}

二、控制器

  在默认情况下,MvcRouteHandler是标准的路由处理程序,这个处理程序将会创建一个MvcHandler的对象实例,在构造函数中,将会把当前的请求参数对象传递给这个实际的处理对象来处理当前的请求,MvcHandler是一个标准的处理程序,但是,它唯一的构造函数需要一个RequestContext类型的参数,所以,并不能被注册到网站的处理程序列表中。

  在MVC模式下,将会通过IControllerFactory接口的对象来获取当前请求的控制器对象。

namespace System.Web.Mvc{
  using Sustem.Web.Routing;

  public interface IControllerFactory{
    IController CreateController(RequestContext requestContext,string controllerName);
    void ReleaseController(IController controller);
  }
}

  实现IControllerFactory接口的对象是控制器的创建工厂,这个工厂通过ControllerBuilder提供给MvcHandler使用。ControllerBuilder的Current属性获取当前的ControllerBuild对象实例,这个类提供了两个方法用户设置或者获取当前的控制器工厂。

public void SetControllerFactory(IControllerFactory controllerFactory)
public IControllerFactory GetControllerFactory()

  1、控制器工厂

  控制器工厂必须实现接口IControllerFactory,其定义在System.Web.Mvc下:

using System.Web.Routing
namespace System.Web.Mvc{
  public interface IControllerFactory{
    IController CreateController(RequestContext requestContext,string controllerName);
    void ReleaseController(IController controller);
  }
}

  2、使用自定义的控制器工厂

  在MVC中获得控制器工厂的方式是借助于ControllerBuilder,这个类使用典型的单例模式创建,我们可以通过其Current属性获取这个唯一对象的引用。   默认情况下,它将会通过DefaultControllerFactory来创建控制器对象,通常情况下,

  • ControllerBuilder.Current.GetControllerFactory方法来获取当前的Controller工厂对象实例
  • ControllerBuilder.Current.SetControllerFactory方法来设置自定义的Controller工厂

  3、为Controller类传递构造函数的参数

  默认情况下,Controller类需要提供默认构造函数,因为DefaultControllerFactory将会通过反射来创建Controller对象的实例。如果我们定义的Controller需要构造函数来创建,或者通过某个IOC的容器来管理Controller,那么可以通过自定义的ControllerFactoru来实现。

  4、Controller的继承关系

  IController是一个非常简单的接口,仅仅定义了一个方法Execute,用来完成针对请求的处理。

using System.Web.Routing;
namespace System.Web.Mvc
{
    public interface IController
    {
        void Execute(RequestContext requestContext);
    }
}

  在MVC中,首先使用ControllerBase实现了IController,并实现了基本的处理逻辑,而真正的处理方法ExecuteCore留到了派生类Controller实现出来。ControllerBase中对接口Execute的实现如下:

protected virtual void Execute(RequestContext requestContext)
{
    if (requestContext == null)
    {
        throw new ArgumentNullException("requestContext");
    }
    VerifyExecuteCalledOnce();
    Initialize(requestContext);
    ExecuteCore();
}
protected abstract void ExecuteCore();

  在派生类Controller中,通过ActionInvoker属性的InvokeAction方法,实现最终对于Action的调用。这个ActionInvoker实际上是一个ControllerActionInvoker对象实例。

protected override void ExecuteCore()
{
  PossiblyLoadTempData();
  try{
    string actionName = RouteData.GetRequiredString("action");
    if(!ActionInvoker.InvokeAction(ControllerContext,actionName))
    {
      HandleUnknownAction(actionName);
    }
  }
  finally{
    PossiblySaveTempData();
  }
}
时间: 2024-11-05 11:00:54

MVC 读书笔记的相关文章

mvc读书笔记

在mvc3的時候引入了Razor.Mvc4中默認的頂級目錄/controllers 保存那些處理URL請求的controller類/models 保存那些表示和操縱數據以及業務對象的類/views 保存那些負責呈現輸出結果的UI模板文件/scripts 保存javascript庫文件和腳本(js)/Images 保存站點使用的圖像/content 保存css和其他站點內容/Filters 保存過濾器代碼.過濾器是一項高級功能/app_data 保存想要讀取/寫入的數據文件/app_start 保

《大型网站技术架构》读书笔记之六:永无止境之网站的伸缩性架构

此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. 首先,所谓网站的伸缩性,指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力.在整个互联网行业的发展渐进演化中,最重要的技术就是服务器集群,通过不断地向集群中添加服务器来增强整个集群的处理能力. 一.网站架构的伸缩性设计 1.1 不同功能进行物理分离实现伸缩 (1)纵向分离:将业务处理流程上得不同部分分离部署,实现系统的伸缩性: (2)横向分离:将不同的业务模块分离部署

《大型网站技术架构》读书笔记之八:固若金汤之网站的安全性架构

此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. 一.网站应用攻击与防御 二.信息加密技术与密钥安全 三.信息过滤与反垃圾 四.电子商务风险控制 五.学习总结 转眼之间,<大型网站技术架构>的读书笔记到此就结束了.最近时间非常紧,因此本篇没有详细对笔记进行介绍(本篇涉及太多内容,而且都是安全相关的).通过本书的学习,我们从高性能.高可用.伸缩性.可扩展性.安全性五个方面的架构学习了每个方面经典的技术方案,虽然以理论偏多,但还是可以从中管中窥豹,一览

Struts2技术内幕 读书笔记三 表示层的困惑

表示层能有什么疑惑?很简单,我们暂时忘记所有的框架,就写一个注册的servlet来看看. index.jsp <form id="form1" name="form1" method="post" action="loginServlet"> <table width="357" border="0" align="center"> <t

【游戏设计模式】之四 《游戏编程模式》读书笔记:全书内容梗概总结

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/53240330 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文的Github版本:QianMo/Reading-Notes/<游戏编程模式>读书笔记 这是一篇超过万字读书笔记,总结了<游戏编程模式>一书中所有章节与内容的知识梗概. 我们知道,游戏行业其实一直很缺一本系

这些基础知识你都了解吗?——《松本行弘的程序世界》读书笔记(上)

1. 前言 半个月之前买了这本书,还是经园子里的一位网友推荐的.到现在看了一半多,基础的都看完了,剩下的几章可做高级部分来看.这本书看到现在,可以说感触很深,必须做一次读书笔记! 关于这本书,不了解的可以去网上查查.作者是Ruby语言的创始人,可谓是程序世界中的高手,开卷有益,不管你是哪个层次的编程人员,相信都能或多或少的汲取到你想要的营养. 下面将总结一下看完本书我记录下的一些知识点.有的是书中的原话,有的是我个人的理解,供参考. 2. 面向对象 2.1 多态性 面向对象三大原则:继承.封装和

读书笔记8网站的安全架构

一.网站应用攻击与防御 二.信息加密技术与密钥安全 三.信息过滤与反垃圾 四.电子商务风险控制 五.学习总结 转眼之间,<大型网站技术架构>的读书笔记到此就结束了.最近时间非常紧,因此本篇没有详细对笔记进行介绍(本篇涉及太多内容,而且都是安全相关的).通过本书的学习,我们从高性能.高可用.伸缩性.可扩展性.安全性五个方面的架构学习了每个方面经典的技术方案,虽然以理论偏多,但还是可以从中管中窥豹,一览大型网站技术的面貌.后面,等我找完工作,拿到offer后,也许会抽出时间去实践下大型网站所使用的

《松本行弘的程序世界》读书笔记

1. 前言 半个月之前买了这本书,还是经园子里的一位网友推荐的.到现在看了一半多,基础的都看完了,剩下的几章可做高级部分来看.这本书看到现在,可以说感触很深,必须做一次读书笔记! 关于这本书,不了解的可以去网上查查.作者是Ruby语言的创始人,可谓是程序世界中的高手,开卷有益,不管你是哪个层次的编程人员,相信都能或多或少的汲取到你想要的营养. 下面将总结一下看完本书我记录下的一些知识点.有的是书中的原话,有的是我个人的理解,供参考. 2. 面向对象 2.1 多态性 面向对象三大原则:继承.封装和

《淘宝技术这十年》读书笔记 (二).Java时代的脱胎换骨和坚若磐石

马云说过"一个好的东西往往是是说不清楚的",姑且不论这句话的对与错.但我真的很佩服<淘宝技术这十年>这本书的作者子柳,能够通过淘宝的一些故事,按照时间顺序和IT发展的各种技术描述清楚,而且过程中读起来非常有意思. 该读书笔记中参杂了很多原文的知识,因为我实在无法割舍,都挺有意思的:同时记录一些有用的知识,通过这本书能介绍些学过的知识或面试中可能出现的题目及作者所思,文章还是非常有趣的,希望对大家有所帮助! 一. Java时代 脱胎换骨 我的师傅黄裳曾经说过"好的架