说到 ASP.NET Web Pages,就不得不先聊聊 Razor 与 ASPX 的故事了。
Razor 模板引擎
Razor 是一种灵活、富有表达能力的模板引擎。它的出色在 ASP.NET MVC 3 以来的各代产品得到了充分的证实,Razor 随着 ASP.NET MVC 3一同发布,伴随着 MVC 3 的大量运用, Razor 也获得了大量的运用,很快超过了 ASPX 模板引擎。甚至其他平台也有了大量的移值,比如 vash for JavaScript。
这里是 ASP.NET Web Pages 官方文档页面 的一个简单的示例代码,它正是一段 Razor 片断:
@{ var total = 7; } @{ var myMessage = “Hello World”; }
1 2 3 4 5 6 7 8 9 10 11 |
<span class="rem"><!-- Inline expressions --></span> <span class="kwrd"><</span><span class="html">p</span><span class="kwrd">></span>The value of your account is: <font style="background-color: #ffff00">@</font>total <span class="kwrd"></</span><span class="html">p</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">p</span><span class="kwrd">></span>The value of myMessage is: <font style="background-color: #ffff00">@</font>myMessage<span class="kwrd"></</span><span class="html">p</span><span class="kwrd">></span> <span class="rem"><!-- Multi-statement block --></span> <font style="background-color: #ffff00">@</font>{ var greeting = "Welcome to our site!"; var weekDay = DateTime.Now.DayOfWeek; var greetingMessage = greeting + " Today is: " + weekDay; } <span class="kwrd"><</span><span class="html">p</span><span class="kwrd">></span>The greeting is: <font style="background-color: #ffff00">@</font>greetingMessage<span class="kwrd"></</span><span class="html">p</span><span class="kwrd">></span> |
在上面的代码中,以 @ 字符开头的即为 C# 代码指令,用于输出一个变量或者包含一段代码逻辑。与 Razor 同时发布的还有 ASP.NET Web Pages 开发方法。
ASP.NET Web Pages
ASP.NET Web Pages 是一种基于 Razor 模板引擎,提供常规 Web 应用程序功能所需扩展而形成的一种轻量级的动态服务器页面的开发方式:它允许你直接在 HTML 里编写动态 C# 代码,并拥有包括处理表单、操作数据,以及使用母版与子视图等所有服务器端 Web 应用程序的功能。
Web Pages 开发机制的基本形式就是,在网站目录中放置一个一个 .cshtml 的 Razor 源文件,比如 default.cshtml、register.cshtml,就可以被访问了——就像 ASPX 时代放置 default.aspx、register.aspx 这样的情况一样。所以可以把 .cshtml 文件理解成另一种 ASPX 页面;只不过它是使用 Razor 语法,比 ASPX 更轻量级,因为它不需要 Code Behind,也没有 ASPX 页面复杂的生命周期,也不支持 ASPX 中那样的用户控件和服务器控件。
如果你的需求相对简单,感觉 ASP.NET MVC 各种 Controller/Action、Route 等概念过于麻烦,而又需要收获即时编译带来的便利,那么 Web Pages 是值得一试的。Web Pages 也支持 Form、QueryString 等功能,同样能访问数据库,调用自己编写的程序集…… 无所不能。
在单页面应用程序(Single Page Application)如此盛行的现在,如果我们的主页面偶尔也需要一些动态能力,比如动态输出压缩后的脚本或 CSS 的路径、动态生成 用于防止跨站提交伪造的令牌数据 等。这种情形使用一个 .cshtml 是非常合适的。
Web Pages 在 ASP.NET 5 中
随着开源策略的实施,不少 ASP.NET 中的原有特性和功能受到了影响。比如 Web Form 开发方法,以及从 Web.Config 读取配置等特性和功能已经不原生提供了。Web Pages 的支持也并没有首先出现在 ASP.NET 5 的开发库列表中,虽然有人说会在将来的 Release 中添加回来,但目前看来官方暂时并不会开发它。
如果和我一样,你也期待这项特性,那么将需要我们为 ASP.NET 5 提供 Web Pages 的支持。幸运地是,ASP.NET 现在是开源的,我们不光能够从源代码了解它的具体运作机制,更能轻松地扩展它。这时节,Web Pages 支持变得可能。下面,分享一下我自己的一个简单实现,目前已能支持 Web Pages 的基本功能。不过目前并没有实现 Web Page 低版本中提供的 UrlData、App、Url 等功能。
基本思路是,开发一个自定义的路由处理程序,它能够试图查找位于磁盘上的 .cshtml 页面文件,并将其编译并执行。当然,有时候我们只需要对一些特定的路径启用 Web Pages 支持。这时我们需要有 Template Routing 能力;如果提供一个扩展名的隐藏,甚至修改功能,那就更酷了。
完整的示例代码在文末可以到,其核心代码如下:
var possiblePaths = GetCandidatePaths(rawUrl);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="rem">// try current file name and the default document for a next level directory</span> IRazorPage razorPage; <span class="kwrd">foreach</span> (var path <span class="kwrd">in</span> possiblePaths) { <span class="kwrd">if</span> (TryCreateRazorPage(pageFactory, path, <span class="kwrd">out</span> razorPage)) { <span class="kwrd">using</span> (Logger.BeginScope(<span class="str">"WebPage: {0}"</span>, rawUrl)) { Logger.LogVerbose(<span class="str">"Executing page {0}"</span>, razorPage.Path); <span class="rem">// todo: authorize the request</span> <font color="#0c47e4">await</font> ExecutePage(context, razorPage); context.IsHandled = <span class="kwrd">true</span>; <span class="kwrd">return</span>; } } } |
我们会调用 Microsoft.AspNet.Mvc.Razor 以及 Microsoft.AspNet.Mvc 的包中提供的相关功能完成 Razor 页面的编译和执行。完成核心代码之后,除了天然拥有 Razor 引擎里提供的自动编译、 Layout 视图、局部视图等能力。借助路由功能,还能可以轻松地拥有默认文档、自定义路由,以及更改 URL 扩展名等特性。
作为一个 ASP.NET 5 应用程序,我们仍然需要 Startup.cs 文件,以下是其中用于映射 Web Pages 支持的代码:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); }
1 2 3 4 5 6 7 8 |
<span class="kwrd">public</span> <span class="kwrd">void</span> Configure(IApplicationBuilder app) { app.UseErrorPage(); app.UseMvc(routesBuilder =>{ routesBuilder.MapAllAsWebPage(); }); } } |
在目录里放置一个 Index.cshtml,并在其中编写若干 Razor 代码后,调用命令启动应用程序:
dnu restore dnx . web |
打开浏览器访问 http://localhost:5000 即可访问并体验当前已成功工作的 Web Page 站点了:
Happy Coding
at: none; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px”>