O 前請提要
在第1期構建項目之后,我們看到項目中有這樣的組成結構:
MyASPWebApplication/
├─obj/
│ └─/一些文件.../
├─Pages/
│ ├─Shared/
│ │ ├─_Layout.cshtml
│ │ └─_ValidationScriptsPartial.cshtml
│ ├─Error.cshtml
│ ├─Error.cshtml.cs
│ ├─Index.cshtml
│ ├─Index.cshtml.cs
│ ├─Privacy.cshtml
│ ├─Privacy.cshtml.cs
│ ├─_ViewImports.cshtml
│ └─_ViewStart.cshtml
├─Properties/
│ └─launchSettings.json
├─wwwroot/(empty)
├─appsettings.Development.json
├─appsettings.json
├─Program.cs
├─Startup.cs
└─MyASPWebApplication.csproj
這是初始生成項目所包含的目錄結構,這里面包含了很多東西,但是,我們還不清楚每個部分能做些什么,充當怎樣的一個角色,以及哪些東西是最基礎的,這一節就來解決這些問題。
在第3期中我們從原理層面上了解了ASP.NET Core Web項目的一個基本的工作流程以及所包含的部分。
I 啟動部分
I.1 Program類
按照絕大部分C#開發框架的慣例,Program類一般是程序的入口,里面包含一個Main函數並被單獨放置於Program.cs中。
小提示:
盡管C#並不像Java那樣強制要求必須將各個數據實體分放到不同的文件中,但C#依然要求定義類的代碼文件必須和該文件中所定義的類(如果多個則任取其一)相同。此外,如非必要,我們仍然建議將各個類定義分離到不同的文件中,除非:
class A與class B之間有比較大的實體關聯,例如依賴關系。class B只是class A的一個輔助工具性的類,例如class B只是針對class A的一個異常類等
ASP.NET Core產生的Program類如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace MyASPWebApplication
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
當然了,這里public static void Main(string[] args)自然就是程序的入口了。里面調用了他的下一個成員函數:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
這個函數的定義方式很特別,它使用了λ推演(=>)的方式做的函數定義,但這無關緊要,實際上表達的是:
public static IHostBuilder CreateHostBuilder(string[] args)
{
IHostBuilder _ = Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults
(
webBuilder =>
{
webBuilder.UseStartup<Startup>();
}
)
return _;
}
這個函數主要調用了Host.CreateDefaultBuilder(args)靜態函數使用程序的參數針對服務主機(Host)的進行一個默認配置。綜上,Program類作為程序的入口,其所包含的配置內容大多面向於項目的頂層設施。
關於服務主機(通用主機、Web主機)的相關概念以及配置過程,在以后期介紹。
I.2 Startup類
在上面的結構中,我們不得不注意的另外項目便是Startup.cs。當然了,本着C#的開發原則,我們很容易了解到這個代碼文件中應當包含一個名為Startup的類。
Startup類位於當前項目的命名空間下(也就是說類全稱為MyASPWebApplication.Startup)。這個類在項目被構建時被生成為這個樣子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace MyASPWebApplication
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
}
I.2.1 這個類干什么呢??
如你所見,這個類並不繼承於任一個其他的現有類,就是一個非常中規中矩的C#類。但事實上,這個類包含了這個Web應用程序被啟動時執行的配置行為。
為什么一個普通的類就可以支配整個項目的配置呢?事實上,盡管被定義為一個普通的類,但Startup還是有一些特征的。
I.2.2 特征??
很明顯,這個類的定義相當簡單,除了構造函數外只有兩個函數和一個只讀屬性:
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
這兩個成員函數的內容,表明了Startup的配置主要是兩個方面:
ConfigureServices函數以控制反轉(IOC)的方式依賴注入(DI)項目中的 服務、Configure函數負責配置請求應用管道
這里面出現了很多概念,比如管道、控制反轉、依賴注入之類的,這將在之后期中慢慢解釋。總之,這些內容是在WebApp運行期間被動態加載的配置。
而這個類最大的玄機在於,它在Program類中被引用過:
//---- Program.cs(節選) ----//
public static IHostBuilder CreateHostBuilder(string[] args)
{
IHostBuilder _ = Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults
(
webBuilder =>
{
webBuilder.UseStartup<Startup>();
}
)
}
第8行中,webBuilder.UseStartup<Startup>()就通過webBuilder加載了這個類作為默認的Host配置。這也正是為什么Startup作為一個普通的類就能夠作為配置類的原因。
I.3 appsettings.json
終於,我們聚焦於不是C#類的一個主要文件了。這是一個json表格式的配置文件。
當然,我們實際上能看到兩個文件:appsettings.json和appsettings.Development.json。這兩個文件的作用實際上沒有什么實質性不同,只是應用的場合並不相同。當項目的運行環境為開發態(Development)的時候,優先使用appsettings.Development.json,否則使用另外一個。
初始狀態下,appsettings.json的內容為:
{
"Logging":
{
"LogLevel":
{
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
這種文件里配置的內容多和數據有關。比如初始狀態下有的"Logging"子表包含了對日志記錄的配置信息。當然,又如當該WebApp使用數據庫時,有關數據庫的連接信息(連接字符串、超時等)也會被配置到這個json表中。
當然,在這張表中,我們也可以加入自己的配置信息,在程序中可以通過Microsoft.Extensions.Configuration.IConfiguration對象讀取這個文件里的配置信息。
關於此文件中包含的配置項和配置方法也會在以后詳細探索。
I.4 launchSettings.json
這個文件存在於Properties文件夾下,定義了項目的屬性:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:64571",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"MyASPWebApplication": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
這個也屬於配置文件,主要配置的是項目的運行環境,例如偵聽端口等、環境模式、是否運行瀏覽器以及IIS反向代理的轉發端口等。
比如,在這個配置模式下,當項目以IIS Express反向代理的方式運行時,就會訪問http://localhost:64571,但如果不使用IIS而直接使用Kestrel來啟動,那么項目地址就是http://localhost:5000。
II wwwroot目錄
另外一個比較顯著的目錄是wwwroot。如果使用Visual Studio創建項目,我們能夠看到,這個wwwroot目錄和Properties目錄類似,有個特別的圖標:

這里面目前是空的,不過這里一般用於放置靜態文件(Static Files)。
II.1 靜態文件??
說白了,就是在運行期間不會發生變化的,一般是指資源文件。
比如:靜態網頁(HTML)、靜態樣式表(CSS)、靜態瀏覽器腳本(JS)、圖片、音頻等等等等。
wwwroot這個目錄就是放這些東西進去的。
服務端處理這些靜態文件是通過StaticFiles這一中間件組成的。
// ---- Startup.cs(節選) ---- //
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
第14行就是Startup類中對此中間件的注冊。
III 常規目錄
為了使項目更為有序的組織,一些文件會被存放於一些目錄(文件夾)中,而這些目錄在ASP.NET Core下有約定的名稱。
III.1 Pages目錄和Views目錄
Pages文件夾存放的內容被稱為頁面,這里用於存放Razor Pages開發模式下的Razor頁面。
Razor Pages是ASP.NET Core 2.x中提出的一種新的開發模式,聚焦於頁面,並以頁面為中心。
在MVC開發模式下,這個部分被替換為視圖,存放於Views文件夾中。盡管兩者之間有所不同,但我們目前要知道的是,這個文件夾里的東西聚焦於前端。
III.1.1 頁面??但是wwwroot里不是也存放頁面了么??
是的,但是wwwroot里面存放的是靜態頁面,而這里面存放的頁面被稱為Razor頁面,是一種動態頁面。
III.1.2 有什么區別么??
當然有區別。雖然說這兩者到瀏覽器客戶端都會被解析為同樣的東西,但是對於服務端而言,這兩者有很大的區別。
存放於wwwroot中的頁面簡單來說就是寫死的頁面,這種頁面無論運行多少次,服務端數據如何變化,其頁面結果是不變的。
但動態頁面是不一樣的,動態頁面是保留了一定不變內容基礎之上又根據后端數據變化而被重新生成的。在瀏覽器上就被體現為,隨着后台數據的變化,頁面的顯示結果會有所不同。
III.1.3 Shared子文件夾
無論是Pages還是Views,因為都存放帶有Razor標記的頁面,所以這兩個目錄下往往還有一個子目錄,稱為Shared。這個目錄主要存放的是共享的分部標記元素(我知道聽不明白,以后會解釋的)。
III.2 Controller文件夾
這個文件夾僅存在於MVC模式下,存放MVC模式當中的控制器(Controller,MVC中的C)。
控制器是一種特殊的類,ASP.NET Core中約定控制器類以Controller結尾。
在MVC中,控制器主要用於處理請求(Request)和路由(Routing)並提供響應。作用有些類似於Java中的Servlet。(具體內容和其他概念的以后介紹,以后介紹)
III.3 Models文件夾
如果WebApp關聯了數據庫,那么數據庫中的數據必然存在一種數據模型,這種數據模型在關系理論中稱為關系模式,它實際上與面向對象理論中的類是對應的。
一般來說因為數據庫的數據組織方式和應用中組織方式的這種不同,因此在項目中處理這些數據就必須自己編寫數據訪問(DA)功能將數據庫中的關系元組轉化成應用可以使用的類對象,但是一個Web項目中的數據門類非常的多,這也就造成了關系模式也非常的多,要編寫的內容也就非常的多,那么為了統一地、自動地處理和顯示這些數據,減輕重復編碼的負擔,一種稱為對象關系映射(ORM)的數據開發模式就產生了。
ORM的機制使得我們只需要在程序中寫出數據模型(類定義),而無需提供存取方法(這個由ORM提供,這個過程也被稱為數據綁定)。那么Models目錄就是為了存放這些數據模型的。
IV 其他
除了上面這些之外,還有其他的東西,遇到再說。
To be continued ...
