MVC框架三大模块

1.Routing模块

Routing机制与MVC5的URL解析处理流程基本是相同的,很多的接口和类像IRouteHandler、IHttpHandler、IController 、RouteBase、RouteTable、RouteDictionary、DefaultControllerFactory以及AreaRegistration名称是相同的功能是类似的,也可以是看做MVC5路由机制的简化版本或者是Artech MVC5书中路由实例的强化版本。在Web项目的启动阶段,设置的路由模板(包括AreaRegistration中的)会被注册到RouteDictionary中,AppDomain中所有实现了IController接口的类型都会被注册到一个线程安全的集合中。

需要重点说明的时候,结合公司现有项目的实战经验(公司的开发规范),MVC项目的路由模板是很正规的,只能是这种形式Area/{otherParameter}/{controller}/{action}/{id},一个Segment只能是”/”或者纯文本字符串或者就单纯是一个大括号参数,不能即有参数又有文本字符串类似”/{date}text{time}/”或者”/{*parameter}/{ohterParameter}/”等等会造成路由复杂的特性(也不能使用RouteAttribute)。也无需RouteConstraint。所以我在解析请求的Url的工作量也降低了不少。

通过遍历缓存的Route集合,以Request作为参数,调用Route的Match方法,对比每个Route中的UrlTemplate和请求Url的虚拟路径,在文本字符串相同,参数位置相符的情况下将请求Url的对应结果或者Route中的默认参数值保存到RouteData的Values字典属性中。在解析出Area,Controller还有Action之后会调用DefaultControllerFactory,依据所匹配Route的DataTokens字典中存储的命名空间还有在项目中配置的默认命名空间来找到满足命名空间还有Controller名的Type。实例化并执行。

2.Action的参数绑定及执行

Action参数配置了五个来源分别是RouteData,QueryString,FormValue,FileCollection还有一个JsonValue,在执行参数绑定的时候,依优先级顺序获取用户指定的特定参数类型的绑定,如果未设置则调用DefaultModelBinder作为默认的绑定。DefaultModelBinder实施绑定还是相当复杂的难以讲述,同时在绑定的过程中还会执行ModelValidator,更新ModelState,总体而言,DefaultModelBinder会判断Action的参数是简单类型还是复杂类型,如果是复杂类型会使用反射解析出所有属性递归调用直到分解成所有简单类型执行绑定,所有复杂类型所分解出的属性会以字符串表达式()的形式传入那五个数据源来匹配是否有值,如果有就更新到ModelState。在表单中有时候需要上传文件,看到Nancy MVC框架中有套文件上传机制是通过解析Header中的boundary Token来获得文件Stream的就修改部分功能,并替换掉上下文然后加入到DrisionMVC中。

在完成参数的绑定后就开始执行Action的真正逻辑了,DrisionMVC为了提高效率,所有的Action都是以Action的MethodInfo为Key包装Action的ActionMethodDispatcher为Value,保存到一个线程安全的ActionMethodDispatcherCache字典中的,ActionMethodDispatcher的Execute方法会完成真正的逻辑执行,Action会被包装到一个LamdaExpression中,形式为Func<object, object[], Task<object>>,该LamdaExpression同样会被缓存,被获取执行就能返回正确的结果。

3.视图cshtml文件的编译执行

View视图文件的编译参照的是RazorEngine框架,所有的.cshtml文件在被第一次编译成C#类后都会被保存到一个线程安全的字典中。该框架的大体运行流程是在控制器的Action方法中返回View()时会调用ViewResult类的ExecuteResult方法,该方法体中开始调用RazorEngine的编译和执行功能,根据约定获取到视图.cshtml文件的绝对路径,以该绝对路径和视图Model的类型(不存在就为null)为组合key,查找缓存中是否存在已经编译好的视图实例,存在就直接返会视图实例,执行视图实例返回一个完整的html字符串文本并写入到Response的Body属性中。如果不存在就会首先获取到.cshtml文件的全部文本,同时新建一个TypeContext的实例包含,Model的Type类型,还有被编译生成的C#类的基类RazorTemplateBase<>还有所必需的的命名空间集合。传入Roslyn编译器生成真正的C#类型并保存。不过现在还有一个问题就是在视图cshtml中应用了@model ModeType之后调用@Html.TextBoxFor等等空间的时候没有智能提示也是挺头疼的,目前暂时使用@inherits来替代。

开发的过程中发现RazorEngine并没有@Html(HtmlHelper)和@Url(UrlHelper)的帮助类,所以在使用DrisionMVC开发Web项目就无法使用控件了,@Html.TextBox,@Html.DropdowList,@Html.Action还有@Url.Action之类的。所以在RazorTemplateBase<>基类中自定义了HtmlHelper,还有UrlHelper两个属性,所有控件的Render机制都与MVC5只是修改成使用OwinContext作为数据源。另外子Action机制还有Partial也是比较复杂的,花了不少的精力。View视图的两大重量级的控件DisplayFor,EditorFor因为公司里面项目都为使用所以未添加。

经过几个月的奋战终于完成了这套MVC框架,在测试应用的过程中问题很少并且没有出现架构级的错误造成某些MVC5常用功能无法实现,也是倍感欣慰。感觉学到了很多的东西,高内聚松耦合的思想也是颇有体会,也学习了不少框架开发的注意事项。

原文地址:https://www.cnblogs.com/Azula/p/6058188.html