ASP.NET MVC 源码分析(一)

  直接上图:

  

  我们先来看Core的设计:

  从项目结构来看,asp.net.mvc.core有以下目录:

ActionConstraints:action限制相关

AntiForgery:防伪相关

ActionResults:action返回对象相关

ApiExplorer:API描述和元数据相关接口

ApplicationModels:应用程序模型相关,应该是全局的model

Areas:地区标签

Filters:大名鼎鼎的过滤器组件

Formatters:格式化相关的东东

Internal:这个从名称看不出是做什么的,打开一看里面是一个路由决策树的实现

ModelBinding:模型绑定,从request 对象取值映射到model的实现

ParameterBinding: ModelBinding的上下文和模型更新入口

Rendering:重量级选手,视图渲染逻辑都在这了

Routing:路由控制相关

ViewComponents:视图组件

剩下的一些零闪的类大致就是controller,controllerFactoary和一些限定请求资源的标签的实现,OK 接下来让我们开始探究吧!

  面对一堆的类我们要从哪开始入手呢?对!我们要找到整个core的生命周期的主线,从主线入手解析相关组件设计,根据ASP.NET整个管道模型的设计(园子讲这个的文章很多,我就不熬述了),我们可以了解到,asp.net.mvc.core  实际上负责的是httphandler生命周期中做的一些事情,他从获取httpContext.Request 对象进行消息路由(Routing),请求过滤(filters,AntiForgery,ActionConstraints),参数映射(比如modelBinding,ParameterBinding),参数验证(比如modelValidate),逻辑处理,最后返回结果(ActionResults),对结果进行渲染输出到流(Rendering,ViewComponents)。

  我们从Microsoft.AspNet.Routing开始看:

  最高层的抽象IRouter,这个路由接口到底做了什么事情呢?

    public interface IRouter
{
Task RouteAsync(RouteContext context); VirtualPathData GetVirtualPath(VirtualPathContext context);
}

  这个接口只有两个方法,一个是RouteAsync根据路由上下文解析路由到相应的处理器上,一个GetVirtualPath负责生成路由的URL,即URL重写asp.net 5为了平台的可移植性,把大部分组件都和system.web 解耦了,以前的版本route的抽象是超类RouteBase负责,包命为System.Web.Routing,废话不多说,上代码:

  public abstract class RouteBase
{
private bool _routeExistingFiles = true; /// <summary>
/// Gets or sets a value that indicates whether ASP.NET routing should handle URLs that match an existing file.
/// </summary>
///
/// <returns>
/// true if ASP.NET routing handles all requests, even those that match an existing file; otherwise, false. The default value is false.
/// </returns>
public bool RouteExistingFiles
{
get
{
return this._routeExistingFiles;
}
set
{
this._routeExistingFiles = value;
}
} /// <summary>
/// When overridden in a derived class, returns route information about the request.
/// </summary>
///
/// <returns>
/// An object that contains the values from the route definition if the route matches the current request, or null if the route does not match the request.
/// </returns>
/// <param name="httpContext">An object that encapsulates information about the HTTP request.</param>
public abstract RouteData GetRouteData(HttpContextBase httpContext); /// <summary>
/// When overridden in a derived class, checks whether the route matches the specified values, and if so, generates a URL and retrieves information about the route.
/// </summary>
///
/// <returns>
/// An object that contains the generated URL and information about the route, or null if the route does not match <paramref name="values"/>.
/// </returns>
/// <param name="requestContext">An object that encapsulates information about the requested route.</param><param name="values">An object that contains the parameters for a route.</param>
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}

  从以上两段代码的区别我们可以看到,移植后的GetRouteData改成了异步的RouteAsync返回了一个task,两个方法的输入参数都构造了自己的上下文环境对象,不在直接从httpContext中操作。啰嗦一句,在.net中我们随处可以见这种基于context上下文的设计,这种基于上下文的设计有什么好处呢,分离关注点,管理环境对象的生命周期灰常的nice.

  打开RouteContext看一下这家伙到底做了些什么:

namespace Microsoft.AspNet.Routing
{
public class RouteContext
{
private RouteData _routeData; public RouteContext(HttpContext httpContext)
{
HttpContext = httpContext; RouteData = new RouteData();
} public HttpContext HttpContext { get; private set; } public bool IsHandled { get; set; } public RouteData RouteData
{
get
{
return _routeData;
}
[param: NotNull]
set
{
_routeData = value;
}
}
}
}

打开一看,尼玛,原来就是httpContext,routeData,IsHandled的一个组合,哈哈,在.net的设计中组合优于继承的思想基本烂大街,httpContext 就不说了,asp.net 生命周期的管控全靠它,isHand一个bool值的属性(我猜估计是指示路由是否完成之类的标识),routeData这个才是route组件独有的东东,看这个名字我们就知道他是一个数据结构,保存的是路由相关的信息:

  

        /// <summary>
/// Creates a new <see cref="RouteData"/> instance with values copied from <paramref name="other"/>.
/// </summary>
/// <param name="other">The other <see cref="RouteData"/> instance to copy.</param>
public RouteData([NotNull] RouteData other)
{
DataTokens = new Dictionary<string, object>(other.DataTokens, StringComparer.OrdinalIgnoreCase);
Routers = new List<IRouter>(other.Routers);
Values = new RouteValueDictionary(other.Values);
}

([NotNull] 这个标签是最新的语法特性,同样体现的是一种声明式编程的思想)我们通过这个构造函数可以知道我们创建routeData的时候需要传入一些可能是路由规则配置的dictionary信息,具体他是怎么工作的,到时候看调用的时候就真相大白了。

  让我们回过头来看VirtualPathContext,由于重写呈现给客户端查看的URL地址肯定是发生在GetRouteData路由之后的,我们可以大胆的猜想他也是持有HttpContext对象和另一些route相关数据对象的组合,果不其然,他的实现没有让我们失望:

    public class VirtualPathContext
{
public VirtualPathContext(HttpContext httpContext,
IDictionary<string, object> ambientValues,
IDictionary<string, object> values)
: this(httpContext, ambientValues, values, null)
{
} public VirtualPathContext(HttpContext context,
IDictionary<string, object> ambientValues,
IDictionary<string, object> values,
string routeName)
{
Context = context;
AmbientValues = ambientValues;
Values = values;
RouteName = routeName;
} public string RouteName { get; private set; } public IDictionary<string, object> ProvidedValues { get; set; } public IDictionary<string, object> AmbientValues { get; private set; } public HttpContext Context { get; private set; } public bool IsBound { get; set; } public IDictionary<string, object> Values { get; private set; }
}

OK,IRouter的介绍到此为止。

下一篇我们将开始介绍IRouteBuilder路由构建者接口,也是route组件的核心。

ASP.NET MVC 源码分析(一)的更多相关文章

  1. ASP.NET MVC源码分析

    MVC4 源码分析(Visual studio 2012/2013) HttpModule中重要的UrlRoutingModule 9:this.OnApplicationPostResolveReq ...

  2. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetPara ...

  3. asp.net mvc源码分析-ModelValidatorProviders 客户端的验证

    几年写过asp.net mvc源码分析-ModelValidatorProviders 当时主要是考虑mvc的流程对,客户端的验证也只是简单的提及了一下,现在我们来仔细看一下客户端的验证. 如图所示, ...

  4. asp.net MVC 源码分析

    先上一张图吧 asp.net请求机制的图  by传智播客邹华栋老师 然后是 邹老师添加MVC请求过程的图 其实MVC 是在.netframework上加了一个过滤器  HttpModule 在C:\W ...

  5. asp.net mvc源码分析-Route的GetRouteData

    我知道Route这里东西应该算路由,这里把它放到mvc里面有些不怎么合适,但是我想大家多数遇到路由都是在mvc的时候吧.首先我们还是来看看GetRouteData方法吧 [csharp] public ...

  6. asp.net mvc源码分析-Action篇 IModelBinder

    我们首先还是看看ReflectedParameterBindingInfo的Binder属性吧: public override IModelBinder Binder {            ge ...

  7. ASP.NET MVC源码分析系列

    Controller下的JsonResult的ExecuteResult方法 public override void ExecuteResult(ControllerContext context) ...

  8. ASP.NET MVC 源码分析(二) —— 从 IRouteBuilder认识路由构建

    我们来看IRouteBuilder的定义: public interface IRouteBuilder { IRouter DefaultHandler { get; set; } IService ...

  9. ASP.NET WebForm / MVC 源码分析

    浏览器 Url:https//localhost:6565/Home/Index ,https//localhost:6565/WebForm1.aspx,请求服务器(构建请求报文,并且将请求报文发送 ...

随机推荐

  1. 在 CentOS 7上安装并配置 Python 3.6 环境

    前言 按照此方法安装保证以下报错什么的统统都没有! 基础环境 系统:centos7.4 软件:python3 Retrying (Retry(total=0, connect=None, read=N ...

  2. PCB SQL SERVER 位运算应用实例

    在PCB行业,一个产品可能同时在多个工厂生产,举例:一个产品一条主记录,这条记录中会对应多个工厂的产地,而这个工厂产地个数不确定, 那么如何设计表结构存储这个不确定的工厂呢?这里想到了4个方式存储 一 ...

  3. codevs1690 开关灯(线段树)

    1690 开关灯 USACO  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond     题目描述 Description YYX家门前的街上有N(2< ...

  4. [Apple开发者帐户帮助]七、注册设备(1)注册一个设备

    您需要已注册的设备来创建开发或临时配置文件.要使用开发人员帐户注册设备,您需要拥有设备名称和设备ID. 注意:如果您使用自动签名,Xcode会为您注册连接的设备.Xcode Server也可以配置为注 ...

  5. selenium3 + python - 异常处理截图 screenshot

    一.截图方法 1.get_screenshot_as_file(self, filename) --这个方法是获取当前window的截图,出现IOError时候返回False,截图成功返回True. ...

  6. UNIX环境高级编程--4

    函数stat fstat fstatat 和 lstat stat函数使用最多的地方可能就是ls -l 命令,用其可以获得有关一个文件的所有信息. 文件类型: (1)普通文件 (2)目录文件 (3)块 ...

  7. JVM 内存区域划分

    一.运行时数据区包括哪几部分? 根据<Java虚拟机规范>的规定,运行时数据区通常包括这几个部分:程序计数器(Program Counter Register).Java栈(VM Stac ...

  8. Android popwindow 消失监听

    LisviewPop.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { //改变显示 ...

  9. C#入门经典 Chapter5 变量的更多内容

    5.1类型转换 1.类型转换 1.1隐式转换:所有情况下可进行,编译器执行转换. 1.2显示转换 强制转换:强迫数据从一种类型转换为另一种类型. (<destinationType>)&l ...

  10. [Windows Server 2008] IIS自带FTP配置方法

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:IIS自带FT ...