ASP.NET MVC的Razor引擎:RazorView
10: protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance);
通过《View编译原理》的介绍我们知道采用Razor引擎的View文件(.cshtml或者.vbhtml)最终都会编译成一个WebViewPage类型,所以通过RazorView/WebFormView体现的View的呈现机制最终体现在对WebViewPage对象的激活。我们可以利用BuildManager根据View文件的虚拟路径得到编译后的类型。从名称也可以看出来,BuildManagerCompiledView内部就是利用了BuildManager根据指定的View文件虚拟路径完成对WebViewPage对象激活。
BuildManagerCompiledView的属性ViewPath表示的就是View文件的虚拟路径,该属性在构造函数中被初始化。BuildManagerCompiledView具有三个构造函数,对象本身的构造逻辑体现在内部构造函数上。如上面的代码片断所示,除了将当前ControllerContext和View文件虚拟路径作为构造函数的参数之外,该构造函数还具有额外两个参数,其类型分别是IViewPageActivator和IDependencyResolver。
上面的代码片断体现了接口IViewPageActivator的定义。顾名思义,该接口旨在实现对WebViewPage对象的激活,基于类型的对象激活机制实现在Create方法中。BuildManagerCompiledView的构造函数中指定的ViewPageActivator被用于初始化内部字段ViewPageActivator,如果没有通过构造函数显式指定ViewPageActivator对象,默认采用的是一个DefaultViewPageActivator对象。
DefaultViewPageActivator是一个具有如下定义的内部类型,我们可以看到它实际上依赖于一个DependencyResolver对象完成针对WebViewPage对象的激活。这个DependencyResolver对象可以通过构造函数进行显式设置,而默认使用的DependencyResolver对象来源于DependencyResolver类型的静态属性Current。
26: return (this._resolverThunk().GetService(type) ?? Activator.CreateInstance(type));
如果我们在构造BuildManagerCompiledView的时候没有指定具体的ViewPageActivator,那么ASP.NET MVC会根据指定的DependencyResolver来创建默认的DefaultViewPageActivator。如果我们只是根据ControllerContext和View文件虚拟路径来构建BuildManagerCompiledView,最终用于激活WebPageView的实际上就是当前的DependencyResolver。换句话说,我们可以通过注册自定义DependencyResolver的方法以IoC的方式来实现对WebPageView的激活,接下来我们会演示相关的实例。
BuildManagerCompiledView对View的呈现机制其实很简单。它调用BuildManager的静态方法GetCompiledType根据指定的View文件虚拟路径得到编译后的WebPageView类型,然后将该类型交给ViewPageActivator激活一个具体的WebPageView对象,并调用其Render方法完成对View的最终呈现。BuildManagerCompiledView将利用激活的WebPageView对象呈现View的逻辑定义在抽象方法RenderView中,而Render方法仅仅实现了根据View文件虚拟路径对WebPageView的激活,具体的实现可以通过如下的代码片断来体现。
11: instance = this.ViewPageActivator.Create(controllerContext, viewType);
15: protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance);
二、RazorView
表示Razor引擎下的View的类型RazorView直接继承BuildManagerCompiledView。如下面的代码片断所示,它具有额外的三个只读属性属性。LayoutPath表示View使用的布局文件的虚拟路径,而RunViewStartPages和ViewStartFileExtensions属性与通过“_ViewStart.cshtml”或“_ViewStart.vbhtml”文件定义的开始页面有关,前者表示是否需要执行开始页面,后者表示开始页面文件的扩展名。对于Razor引擎默认创建的RazorView,RunViewStartPages属性为True(意味着总是会执行开始页面)。ViewStartFileExtensions属性表示的字符串集合包含两个元素“cshtml”和“vbhtml”。
3: public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable string viewStartFileExtensions);
4: public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable string viewStartFileExtensions, IViewPageActivator viewPageActivator);
6: protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance);
RazorView通过实现RenderView方法最终完成了对View的呈现。方法传入参数instance是通过BuildManagerCompiledView激活的View对象,通过上面的介绍我们知道这是一个空的WebViewPage TModel 对象(默认情况下是通过默认构造函数创建的)。RazorView在RenderView方法中对其进行初始后调用ExecutePageHierarchy方法将整个页面内容呈现出来。RazorView实现RenderView方法的逻辑基本上可以通过如下的代码片断来表示。
4: protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
14: startPage = StartPage.GetStartPage(page,"_ViewStart",this.ViewStartFileExtensions);
17: page.ExecutePageHierarchy(new WebPageContext(viewContext.HttpContext, null, null), writer, startPage);
为了让读者了解RazorView实现 View呈现的本质,我们按照其实现原理自定义一个简单的RazorView类型。我们在一个ASP.NET MVCWeb应用中定义了如下一个表示自定义RazorView的SimpleRazorView类型。SimpleRazorView直接实现了IView接口,在构造函数中初始化的属性ViewPath表示View文件的虚拟路径。
21: WebPageContext pageContext = new WebPageContext(viewContext.HttpContext, null, null);
22: WebPageRenderingBase startPage = StartPage.GetStartPage(page,"_ViewStart",new string[]{"cshtml","vbhtml"});
在用于呈现View的Render方法中,我们利用BuildManager根据当前View文件的虚拟路径得到动态编译后的类型,然后利用该类型以反射的方式创建一个WebViewPage对象。接下来我们初始化该WebViewPage对象的VirtualPath、VirewContext和ViewData属性,并调用InitHelpers方法对HtmlHelper、UrlHelper和AjaxHelper进行初始化。
SimpleRazorView总是会执行开始页面,所以我们通过调用ViewStartPage的静态方法GetStartPage根据指定的开始页面文件名(_ViewStart)和扩展名列表(cshtml和vbhtml)得到表示开始页面的WebPageRenderingBase对象。最后我们创建WebPageContext对象,并将它和表示开始页面的WebPageRenderingBase对象作为参数调用WebViewPage的ExecutePageHierarchy方法实现对整个页面的呈现。
为了验证SimpleRazorView能够正常完成对View内容的呈现,我们定义了如下一个HomeController。在默认的Action方法Index中,我们创建一个Contact对象作为当前ViewData的Model。然后通过指定View文件的虚拟路径(“~/Views/Home/Index.cshtml”)创建我们自定义的SimpleRazorView对象。最后我们创建ViewContext,并将其作为参数调用SimpleRazorView的Render方法将默认的View呈现出来。
9: SimpleRazorView view = new SimpleRazorView("~/Views/Home/Index.cshtml");
10: ViewContext viewContext = new ViewContext(ControllerContext, view, ViewData, TempData, Response.Output);
我们的View很简单,如下面的代码片断所示,这是一个Model类型为Contact的强类型View,在该View中我们直接调用HtmlHelper TModel 的扩展方法EditorForModel将作为Model的Contact对象以编辑模式呈现在一个表单之中。
为了验证我们自定义的SimpleRazorView对布局文件和_ViewStart页面的支持,我们在“~/Views/Shared/”目录下定义了如下一个名为“_Layout.cshtml”的布局文件。布局文件的设置通过定义在“~/Views/”目录下具有如下定义的“_ViewStart.cshtml”文件来指定。
运行我们的程序后直接会在浏览器中呈现如下图所示的效果,可以看出这和我们直接在Action方法Index方法返回一个ViewResult对象没有本质的区别。
ASP.NET MVC的Razor引擎:View编译原理
ASP.NET MVC的Razor引擎:RazorView
ASP.NET MVC的Razor引擎:IoC在View激活过程中的应用
ASP.NET MVC的Razor引擎:RazorViewEngine
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 原文链接
基于Asp.Net Mvc开发的个人博客系统 一个基于Mvc 5构建的简单、代码层级分明的开源个人博客系统。前端美观大气、后台采用RightControl .NET通用角色权限系统,开发简单、效率高。网站配置采用XML配置,灵活可以根据自己是需求进行个性化配置。系统功能完备,完全可以满足需求,基本不用二次开发,非常使用程序员的个人博客。
Java Spring Boot开发实战系列课程【第7讲】:Spring Boot 2.0安全机制与MVC身份验证实战(Java面试题) 立即下载
相关文章
- 学习ASP.NET Core Blazor编程系列十四——修改
- abp(net core)+easyui+efcore实现仓储管理系统——EasyUI之货物管理一 (十九)
- .NET 采用 SkiaSharp 生成二维码和图形验证码及图片进行指定区域截取方法实现
- Keras.NET
- Asp.Net Core WebApi6解决跨域问题
- ASP.NET MVC学习系列(二)-WebAPI请求
- Dependency injection in ASP.NET Core
- asp.net mvc验证那些事
- What are 'closures' in .NET?
- Secure a Web API with Individual Accounts and Local Login in ASP.NET Web API 2.2
- RSA in .net and dotnet core
- ASP.NET Razor - C# and VB Code Syntax
- ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案 try.dot.net 的正确使用姿势 .Net NPOI 根据excel模板导出excel、直接生成excel .Net NPOI 上传excel文件、提交后台获取excel里的数据
- 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问
- 通过源码了解ASP.NET MVC 几种Filter的执行过程 在Winform中菜单动态添加“最近使用文件”
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
- MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
- Word格式处理控件Aspose.Words for .NET教程——使用DocumentBuilder将字段插入文档
- net-snmp开发中出现“Error opening specified endpoint"" ”的解决方案
- ASP.NET Core - 依赖注入(一)
- ASP.NET WebForm和Mvc开发的比较
- ASP.NET Web API实践系列02,在MVC4下的一个实例, 包含EF Code First,依赖注入, Bootstrap等
- 微信-JSSDK .NET版
- 《ASP.NET MVC 4 实战》----1.2 ASP.NET MVC是什么
- 基于ASP.NET+SQL Server简单的 MVC 电商网站【100010406】
- ASP.NET Core1.0 带来的新特性
- 301重定向代码合集(iis,asp,php,asp.net,apache)
- 采用Fiddler建立Asp.net webapi与Android/IOS调试环境
- Asp.net固定功能位充满了零(解决,演示样本)!
- ASP.NET学习总结
- asp.net web api 如何设置允许后台跨域访问
- 【ASP.NET】Global.asax与Web.config