原文:http://docs.asp.net/en/latest/conceptual-overview/understanding-aspnet5-apps.html
英文捉急,花了挺多时间的,希望看到的同学能有所收获,有错误的地方请指正。
对于理解如何快速构建 web apps ,ASP.NET 5 引入了一些非常重要的新基本概念。这些概念在 web 编程中不是最新的,但往往对习惯使用 ASP.NET 和 Visual Studio 的开发者来说可能比较陌生。
In this article:
ASP.NET Project Structure(项目架构)
ASP.NET 5 的项目架构新增了新的概念并且替代了老版本 ASP.NET 项目包含的元素。新的默认 web 项目模板创建了一个解决方案并且项目架构如下:
第一个你可能注意到的是这个新框架有一个包含 global.json 的 Solution Items 文件夹,并且web项目本身的路径在解决方案的 src 文件夹中。新架构也包含了一个特殊的 wwwroot 文件夹,和一个 Dependencies(依赖)块用于引用的内容,就像以往ASP.NET项目的 References(引用)一样。根目录中项目有一些新文件如 bower.json,config.json,gruntfile.js,package.json,project.json 和 startup.cs。你可能注意到 global.asax,package.config 和 web.config 不见了。在以往 ASP.NET 版本中,很多程序配置会放在这些文件中。在 ASP.NET 5 中,这些信息与逻辑被重构到更小、职责更专一的文件中。
Framework Target(目标框架)
ASP.NET 5 可以指定多个 framework,允许应用程序被发布到不同的 hosting 环境中。默认情况下程序会指定完整版本的 .NET,但是也可以指定 .NET Core。大部分迁移的程序会指定全功能的ASP.NET 5框架,至少一开始是这样,是由于它们可能很多依赖包含在今天 .NET Core 还没有这些功能的在基础类库中。.NET Core 是 .NET framework 的小版本,优化了web程序并且支持Linus和Mac环境。它可以部署在程序中,允许一个server中不同程序指定不同版本的.NET Core。它也是模块化的,允许按需功能附加,如单独的NuGet包。 (learn more about .NET Core).
通过在在 Solution Explorer 中右击 web 项目并选择 Properties,你能看到哪个框架目前被指定到web程序项目的属性中:
默认情况下,Use specific DNX version的勾选框是不选的。指定一个特定版本,点勾选框并选择对应版本、平台和架构。
The project.json File
project.json 文件 ASP.NET 5 的新东西。它被用于定义项目的服务端依赖(server side dependencies,下面会讨论),还有其他一些项目特定信息。project.json的默认内容模板如下:
webroot 这一节指定了执行网站的文件夹,按照约定默认是 wwwroot 文件夹(the wwwroot folder)。Version属性指定了项目当前的版本。你可以定义其他关于项目的元数据,如authors、description。
ASP.NET 5对命令行有非常好的支持,并且commands节允许配置确定的命令行指令(例如,启动web site或run tests)
"commands": {
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000",
"gen": "Microsoft.Framework.CodeGeneration",
"ef": "EntityFramework.Commands"
},
frameworks 这一节指定了哪个framework会被build,哪些依赖需要被包含。例如,如果你用LINQ和集合,你可以通过把它们增加到 dnxcore50
列表依赖来确定时候包含在了你的.NET Core build中,如下所示。
延伸阅读:Diagnosing dependency issues with ASP.NET 5
exclude 节被用于识别应该在包含在 build 中的文件和文件夹。同样,bundleExclude 被用于识别 bunding 时应该包含 到网站中的内容(例如,在生产环境中)。
scripts 节被用于指定对于特定 build 的自动化脚本。Visual Studio 现在内置支持在特定事件之前或之后运行这些脚本。默认的 ASP.NET 项目模板已经包含在运行 postrestore 和 prepare 时通过 npm 和 bower 安装 client side dependencies。
The global.json File
global.json 文件被用于配置整个解决方案。它默认只包含2节,sources
和 sdk
。
{
"projects": [ "src", "test" ],
"sdk": {
"version": "1.0.0-beta5-11584"
}
}
source 属性指定了解决方案中包含源码的文件夹。默认情况下项目架构把文件放在 src 文件夹中,允许在同级目录中构建工件,更简便地从源码控制中排除。
The wwwroot folder
在先前的 ASP.NET 版本中,项目的根目录通常就是网站根目录。如果你把一个 Default.aspx 文件放在一个早期版本的 ASP.NET 中,如果有对 web 程序根目录的请求时就会加载。在之后的 ASP.NET 版本中,增加了路由的支持,解耦了文件路径和对应的URL(因此,Controllers 文件夹中的 HomeController 可以使用默认实现的路由处理根目录的服务请求)。不管如何,路由只能用于特定的程序逻辑,客户端展示页面时无需静态文件支持。图片、脚本文件、样式等资源仍然普遍基于程序的文件架构加载,而非项目根目录。
基于文件的方式存在一些问题。首先,保护敏感项目文件需要框架级的文件名与扩展名保护,以阻止 web.config 或 global.asax 之类的东西被客户端请求。特别地阻止特定文件的访问(也称为黑名单)远远没有赋予权限去访问文件安全(也成为白名单)。通常对于 dev/test 和 production 也有不同版本的权限 (例如 web.config)。开发中,脚本通常会单独分离并且放在可读格式中,但是在生产部署中会最小化并且绑定在一起。对只部署生产文件到生产环境有利,但是在前期架构中处理这类的情况却非常棘手。
进入 ASP.NET 5 的 wwwroot 文件夹。wwworrt 文件夹代表了实际 web 程序在 web server 中运行的根目录。静态文件,如 config.json,不放在 wwwroot 中的话永远是无法访问的,而且没必要再创建阻止访问敏感文件的规则了。对比黑名单阻止访问敏感文件,在 web 请求中只能访问 wwwroot 的白名单更加安全。
还有个好处是,wwwroot 文件夹还简化了通用的任务如 bundling(捆绑) 和minification(最小化),使得现在能更加简便的合成到一个标准 build process 和自动化工具如 Grunt。
Client Side Dependency Management
Dependencies 文件夹包含了2个子目录:Bower 和 NPM。这些文件夹关联到2个同名的包管理器,并且它们被用于获取客户端依赖和工具(例如 jQuery、bootstrap 或 grunt)。展开文件夹后能看到目前被工具管理着的依赖与当前被项目使用的版本。
bower 依赖被 bower.json 文件控制。你会注意到上图的每个 items 列表关联到 bower.json,如下:
bower.json 文件中,每个依赖被进一步地配置在它们本身的节当中,指明了当 bower 任务执行时将如何向 wwwroot 文件夹部署。
默认地,bower 任务使用 gulp 执行,gulp 被配置在 gulpfile.js 中。目前 web 模板的 gulpfile,包含了从 bower 文件夹复制 copying 和 cleaning 脚本与 CSS 文件到 wwwroot 中的 /lib
文件夹的任务。
Server Side Dependency Management
References 文件夹列出了项目的服务端的引用细节。ASP.NET 开发者应该对它比较熟悉,但它已经被修改成区分了不同架构目标(framework target)的不同引用,如全功能的 ASP.NET 5.0 与 ASP.NET Core 5.0。在每个架构目标中,你会找到分离的引用,它们的图标指明了引用究竟是一个 assembly,一个 NuGet package,还是一个项目。要注意的是这些依赖会在编译时被检查,缺失的依赖会从配置的 NuGet package 源下载(特指配置:Options - NuGet Package Manager - Package Sources)。
Configuring the Application
ASP.NET 5 不再存放配置在 XML 文件中(web.config 和 machine.config)。配置现在被放在 config.json中,它特别被设计为存放 app configuration settings。默认的 ASP.NET 项目模板在 config.json 文件中包含 Entity Framework 和特定的 database connection string 细节。
config.json 中的单独条目不局限于 name-value pairs的形式,可以指定 rich objects。条目还可以引用其他条目,你能看到 EF 是如何配置的,如上图。
config.json 文件名没啥特别的 - 它被 Startup.cs 中的名称指定了。你能添加许许多多对你的程序有用的配置文件,好过放在过于庞大的 web.config 文件中。你还能不局限于使用 JSON 格式文件 - 你愿意的话,仍可以使用 XML 甚至 .INI 文件。
访问配置数据最好的方式是注入 IConfiguration <https://github.com/aspnet/Configuration/blob/dev/src/Microsoft.Framework.ConfigurationModel.Interfaces/IConfiguration.cs>``_ interface into your controller, and then simply calling its ``Get
方法,使用你需要的配置元素名称。例如,在配置中存储程序名称并且把它显示到 About 页面中,你会需要在默认项目中作3个改变。首先,在 project.config 中增加入口。
其次,确保 ASP.NET 知道当一个构造器需要 IConfiguration
实例时会得到什么。这种情况,我们可以指定配置值为单例,因为我们不希望它在程序生命周期中变化。某一刻我们会处理 Startup.cs,但在这一步,仅仅在 Startup.cs 中 ConfigureServices() 方法结尾中增加1行:
services.AddSingleton(_ => Configuration);
最后一步也是第三步是指定一个 IConfiguration
实例,你的 controller 会通过构造器使用它。在类中遵循按照 Explicit Dependencies Principle 是一个很好的习惯,并且使 ASP.NET 5 内置的依赖注入能正常工作。分配实例给本地字段,然后通过调用 Get
实例方法访问配置值。
你会需要确保这个 using 声明:
using Microsoft.Framework.ConfigurationModel;
然后,更新 controller,如下:
运行程序并导航到 About 页面,你会看到结果。
Application Startup
ASP.NET 5 已经把功能集分离到多种模块中,这些模块可以单独增加到一个 web 程序中。这允许不导入没用的功能,以达到精简 web 程序的效果。当你的 ASP.NET 程序运行,ASP.NET 运行时调用 Startup
类 中的 Configure
。如果你使用空模板创建一个新的 ASP.NET web 项目,你会发现 Startup.cs 文件只有几行代码。默认 Web 项目的 Startup
类连接了配置、MVC、EF、Identity services、logging、routes,以及更多。它为如何配置你的 ASP.NET 程序使用的服务提供了一个很好的例子。例子中的 startup 类有3个部分:构造器、ConfigureServices
和 Configure
。Configure
方法在 ConfigureServices
之后被调用并且被用于配置中间件。
构造器指定了配置会如何被程序处理。配置是 Startup
类的一个属性,并且可以从多种文件格式或环境变量中被读取。默认的项目模板连接了 Configuration
去使用一个 config.json 和环境变量。
public Startup(IHostingEnvironment env)
{
// Setup configuration sources.
Configuration = new Configuration()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
}
ConfigureServices
方法被用于指定哪些服务在程序中是可用的。默认模板使用 helper 方法去增加 EF、Identity 和 MVC 使用的多种服务。这也是你可以增加你自定服务的地方,就以上那样,我们暴露了配置服务。完整的 ConfigureServices
方法,包含了调用增加单例 Configuration
,如下:
// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<ApplicationDbContext>();
// Add Identity services to the services container.
services.AddIdentity<ApplicationUser, IdentityRole>(Configuration)
.AddEntityFrameworkStores<ApplicationDbContext>();
// Add MVC services to the services container.
services.AddMvc();
services.AddSingleton(_ => Configuration);
}
最后,Configure
方法会在 ConfigureServices
之后被运行时调用。在例子的项目中,Configure
被用于激活一个 console logger、增加几个有用的功能到开发环境、增加静态文件、Identity 和 MVC 路由的支持。注意增加 Identity 和 MVC 到ConfigureServices
还不够 - 它们还需要通过 Configure
中的调用被配置在请求管道中。
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
// Configure the HTTP request pipeline.
// Add the console logger.
loggerfactory.AddConsole();
// Add the following to the request pipeline only in development environment.
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
app.UseBrowserLink();
app.UseErrorPage(ErrorPageOptions.ShowAll);
app.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
}
else
{
// Add Error handling middleware which catches all application specific errors and
// send the request to the following path or controller action.
app.UseErrorHandler("/Home/Error");
}
// Add static files to the request pipeline.
app.UseStaticFiles();
// Add cookie-based authentication to the request pipeline.
app.UseIdentity();
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
}
如你所见,在 Startup
类 中,服务已经可用,并且请求管道也配置好了,与通过 web.config 管理 HTTP Modules 和 Handlers 的方式是不同的。
Summary
ASP.NET 5 介绍了一些之前 ASP.NET 版本没有的概念。与其使用 web.config、packages.config 和存储在 .csproj/.vbproj 文件中的多种项目属性工作,开发者现在可以使用专注于特定用途的特定的文件和文件夹工作。
尽管一开始需要一些学习曲线,最终结果是更加安全、更加可维护、更好的源控制,和比以往 ASP.NET 版本更好的关注点分离方案。