在本篇文章中,你可以了解ASP.NET Core是如何運行在IIS上下文中的,怎樣才能把ASP.NET Core應用程序發布在IIS上。
IIS和ASP.NET Core
關於ASP.NET Core,最重要的一點就是它托管於一個獨立運行的控制台程序。它不用托管在IIS中,也不依賴IIS。ASP.NET Core應用程序有自托管的Web服務器,並且可以使用這個自托管的服務器實例在內部處理請求。
經典的ASP.NET托管
ASP.NET Core與IIS
ASP.NET Core則完全不同,它並不是運行在IIS的工作進程中,而是獨立運行的。它運行於控制台應用程序之中,控制台中則運行了Kestrel Web服務器組件。Kestrel作為一款.NET Web服務器的實現,它在吞吐量性能方面做了很多工作。它可以快速將來自網絡的請求接入到應用程序中,但是它僅僅是一個最基本的Web服務器。它沒有類似IIS的Web管理服務,也沒有IIS那么多的功能。
當選擇在Windows平台上運行時,將IIS作為Kestrel的前置服務器可以獲得額外一些基礎功能。比如通過主機頭的80/443端口轉發、處理生命周期管理和證書管理等。
ASP.NET Core程序獨立運行在控制台應用程序中,並通過dotnet運行時命令調用。它並沒有被加載到IIS工作進程中,但是IIS卻加載了名為AspNetCoreModule的本地Module,這個Module用於執行外部的控制台程序。
AspNetCoreModule是作為ASP.NET Core Server Hosting Bundle的一部分被安裝在服務器上的。
AspNetCoreModule作為IIS本地Module,在IIS處理管道周期的最開始就能hook到請求,緊接着就將所有請求重定向到后端的ASP.NET Core程序。這里是所有的請求,也就是說即便是頂級的映射Handler,比如aspx。這些都將從IIS管道中分流到ASP.NET Core中處理。這意味着,沒法簡單的將ASP.NET Core和其他框架放在同一個站點(虛擬目錄)中。這看起來有點退步了,因為在此之前可以混合使用不同框架。
AspNetCoreModule的作用是確保在第一個請求來之前你的程序已經加載好了,並且保證ASP.NET Core在由於某些原因崩潰后的重啟工作。這實際上和被WAS(Windows Activation Service)管理的經典ASP.NET程序是一樣的。
當程序運行起來后,AspNetCoreModule會處理接入的Http請求,並將其路由到ASP.NET Core程序中。
因此,來自Web的請求進入到內核模式,由http.sys驅動程序路由到IIS的主要端口(80)或SSL端口(443)上。請求接着被轉發到ASP.NET Core程序配置的非80/443端口中。從本質上來說,IIS在這里扮演的是反向代理的角色,它僅僅簡單的將請求轉發到運行在Kestrel Web服務器上不同端口的ASP.NET Core程序里。
Kestrel接收到請求,並將其推送到ASP.NET Core的中間件處理管道中,該處理管道稍后將處理這個請求並將請求傳入到應用程序邏輯代碼中。HTTP的輸出結果會再次傳回到IIS,接着IIS將結果通過Internet返回給初始化這個請求的客戶端,它可能是瀏覽器、手機客戶端或者一個應用程序。
AspNetCoreModule配置在位於應用程序根目錄的web.config文件中。配置文件定義了用來加載.NET Core程序的啟動命令(dotnet)和參數(應用程序主dll)。web.config文件中的配置標明了需要加載的應用程序模塊和啟動DLL的根目錄。
1 <?xml version="1.0" encoding="utf-8"?><configuration> 2 <!-- 3 Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380 4 --> 5 <system.webServer> 6 <handlers> 7 <add name="aspNetCore" path="*" verb="*" 8 modules="AspNetCoreModule" resourceType="Unspecified" /> 9 </handlers> 10 <aspNetCore processPath="dotnet" arguments=".\AlbumViewerNetCore.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" /> 11 </system.webServer> 12 </configuration>
還需要IIS么?
前面已經討論過在Windows上運行ASP.NET Core時,推薦將IIS作為前置代理。然而直接通過IP地址和端口也是可以訪問Kestrel的,但還是有理由可以說服你不在生產環境中直接暴露應用程序。
首先,當你在單個服務器上運行多個應用程序,並且需要共享80和443端口時,直接運行Kestrel就不行了。Kestrel不支持多個80端口綁定到單個IP地址的主機頭路由方式。拋開IIS(實際上是http.sys),目前為止單獨使用Kestrel是無法實現的(並且我想這也不在計划中)。
運行在IIS中的AspNetCoreModule同時提供了必要的進程管理措施,它可以確保程序在首次訪問前已經被加載好,也可以確保程序持續運行即便在崩潰后也可以重新啟動。AspNetCoreModule提供的必要進程管理來保證AspNetCore程序即便是在崩潰之后也始終可用。
讓IIS處理SSL請求也是很好的選擇,通過IIS的證書存儲區設置證書,並讓IIS正確處理SSL認證。從IIS出來到應用程序的請求可以是一個非安全的HTTP請求。這意味着只有一個前置的IIS服務器需要證書,即便是你后面有多個真正提供http內容的服務器。
IIS還可以提供靜態文件服務、靜態文件的gzip壓縮、靜態文件緩存、Url重定向和IIS本地可以提供的其他功能。IIS實際上在處理非應用程序請求時即好又高效,所以很值得利用IIS的這些優勢。讓IIS處理它擅長的任務,讓剩下的動態任務傳遞給ASP.NET Core程序來處理。
不要把IIS作為開發時服務器
我經常會遇到類似這種問題:
我可以像之前開發經典ASP.NET Web應用程序那樣在IIS中運行和調試ASP.NET Core程序么?
讓我們先把這個問題放一邊,幾乎沒有理由在開發過程中使用IIS。的確,在過去,完全在IIS中開發是有必要的,因為IIS和IIS Express兩者在某些方面存在一些不同的行為。
然而,在使用ASP.NET Core的情況下就完全沒有理由再考慮在開發過程中使用IIS。這是為什么?因為ASP.NET Core程序並不是運行在IIS內部的。無論是從IIS或IIS Express中的調用或直接從命令行使用dotnet run命令,實際運行的都是同一套代碼並且大多數情況下是在完全相同的運行環境中。在IIS內部運行就不能簡單的使用命令行環境下模擬了。
“運行”IIS
在調試環境中,不能“僅僅運行IIS”,這是因為ASP.NET Core程序必須得先發布,然后才能執行。開發文件夾中並沒有包含所有運行程序所需的文件。當選擇“調試”或“運行”程序時,首先會將程序發布到一個單獨的地方,再從那里運行。由於這個原因,你Visual Studio的例子中就看不到IIS選項了。
如果非要在IIS下運行,那么你得先將程序發布到本地文件夾中,然后將該文件夾配置為IIS的虛擬目錄或站點,接着就可以運行了。
向IIS發布ASP.NET Core程序
為了在IIS下運行程序,第一步就是要將應用程序發布出來。現在,提供了兩種發布方式:
- 使用dotnet publish命令
- 使用Visual Studio的發布功能
使用 dotnet publish
dotnet publish構建程序並將一個可運行、自托管的項目版本拷貝到磁盤的新位置。你可以指定一個輸出文件夾作為發布文件的存放處。這與在經典ASP.NET中將Web站點發布到一個臨時文件夾類似。在ASP.NET Core中顯示選擇在某個路徑下發布程序,這樣文件不再會隱藏,也不會四處復制。
這表示將程序發布到c:\temp\AlbumViewerWeb。
IIS托管發布文件夾指導
當應用程序發布后,將其復制到服務器上(通過FTP或其他方式),接着就可以將IIS和這個文件關聯起來。
要注意我創建的這個AspNetCore應用程序池,要把它的.NET運行時設置為前面所說的非托管代碼。
現在,可以瀏覽網站或虛擬目錄,應用程序同時也就跑起來了。
現在把本地發布的網站拷貝到Web服務器上(通過FTP或直接拷貝文件或者其他方式),設置好站點或虛擬目錄就可以了。
從Visual Studio發布
dotnet publish這步將整個項目拷貝到另一個文件夾中,但這實際上並沒有將項目發布為網站(目前,還需要稍微等一會)。
使ASP.NET Core應用程序增量發布是非常重要的,你需要使用MsDeploy來管理這么多的依賴項,MsDeploy是作為Visual Studio Web發布功能的一部分。
目前,Visual Studio的圖形工具還是有缺陷的的,但是底層的功能是支持的。這里按照我做出的一些調整,然后就可以使用了。
當你使用Visual Studio的RC2 Web工具和發布對話框時,你發現無法創建針對IIS的發布概要。這里只有文件和基於Azure的發布選項,沒法直接通過界面創建新的Web網站發布。
特定版本的解決方法
很顯然,這個問題在RC2之后的版本會得到更新。所以,當你在一個月后讀到本文的這些步驟時,請先確認下是否可以直接通過Visual Studio界面完成IIS發布。
在ASP.NET Core Web項目中創建“手動概要”:
- 創建文件夾\Properties\PublishProfiles
- 創建文件<MyProfile>.pubxml
1 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2 <PropertyGroup> 3 <WebPublishMethod>MSDeploy</WebPublishMethod> 4 <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> 5 <LastUsedPlatform>Any CPU</LastUsedPlatform> 6 <SiteUrlToLaunchAfterPublish>http://samples.west-wind.com/AlbumViewerCore/index.html</SiteUrlToLaunchAfterPublish> 7 <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> 8 <ExcludeApp_Data>False</ExcludeApp_Data> 9 <PublishFramework>netcoreapp1.0</PublishFramework> 10 <UsePowerShell>True</UsePowerShell> 11 <EnableMSDeployAppOffline>True</EnableMSDeployAppOffline> 12 <MSDeployServiceURL>https://publish.west-wind.com</MSDeployServiceURL> 13 <DeployIisAppPath>samples site/albumviewercore</DeployIisAppPath> 14 <RemoteSitePhysicalPath /> 15 <SkipExtraFilesOnServer>True</SkipExtraFilesOnServer> 16 <MSDeployPublishMethod>RemoteAgent</MSDeployPublishMethod> 17 <EnableMSDeployBackup>False</EnableMSDeployBackup> 18 <UserName>username</UserName> 19 <_SavePWD>True</_SavePWD> 20 <ADUsesOwinOrOpenIdConnect>False</ADUsesOwinOrOpenIdConnect> 21 <AuthType>NTLM</AuthType> 22 </PropertyGroup> 23 </Project>
AuthType NTLM修正
注意文件底部的<AuthType>NTLM</AuthType>鍵。此鍵非常重要,如果錯誤發布操作將無法執行。如果是從一個現有的文件拷貝過來的,請確保此鍵的設置。
此時,你就可以將網站發布到遠程服務器上的IIS中,並且可以增量更新內容。
