在IIS上發布並運行ASP.NET Core


英文原文地址:https://weblog.west-wind.com/posts/2016/Jun/06/Publishing-and-Running-ASPNET-Core-Applications-with-IIS 當構建一個ASP.NET Core應用程序並且計划將其運行在IIS中時,你會發現Core應用程序和之前版本的ASP.NET程序在IIS中的運行方式是完全不一樣的。

在本篇文章中,你可以了解ASP.NET Core是如何運行在IIS上下文中的,怎樣才能把ASP.NET Core應用程序發布在IIS上。

IIS和ASP.NET Core

關於ASP.NET Core,最重要的一點就是它托管於一個獨立運行的控制台程序。它不用托管在IIS中,也不依賴IIS。ASP.NET Core應用程序有自托管的Web服務器,並且可以使用這個自托管的服務器實例在內部處理請求。

不過,你可以將IIS作為ASP.NET Core應用的前置代理。這是因為Kestrel是一個最基礎的Web服務器,它並不像IIS這樣一個完整Web服務器,有一些特性Kestrel是不支持的。為了提供80/443前置端口,推薦在Windows平台上使用IIS,因為kestrel無法直接提供這種使用方式。對於IIS(或其他反向代理)來說,即便是在ASP.NET Core應用程序中,也仍將作為服務器的一部分扮演着重要的角色。現在我們一起看一下IIS是如何和ASP.NET Core應用相配合的。 

經典的ASP.NET托管

在正式了解ASP.NET Core托管前,讓我們回顧一下運行ASP.NET應用程序經典ASP.NET模式。  在經典ASP.NET應用程序中,所有一切都托管在IIS工作進程中(w3wp.exe),這也被稱為IIS應用程序池。ASP.NET程序被托管在應用程序池中,並且被按照IIS內建的ASP.NET托管特性所實例化。當請求從http.sys傳入到ASP.NET應用程序管道時,本地運行時管理器會實例化一個代表應用程序的.NET運行時,同時引入HttpRuntime對象用來處理這個請求。來自http.sys的請求被派送到對應的應用程序池和HttpRuntime實例的托管站點。

ASP.NET Core與IIS

ASP.NET Core則完全不同,它並不是運行在IIS的工作進程中,而是獨立運行的。它運行於控制台應用程序之中,控制台中則運行了Kestrel Web服務器組件。Kestrel作為一款.NET Web服務器的實現,它在吞吐量性能方面做了很多工作。它可以快速將來自網絡的請求接入到應用程序中,但是它僅僅是一個最基本的Web服務器。它沒有類似IIS的Web管理服務,也沒有IIS那么多的功能。

當選擇在Windows平台上運行時,將IIS作為Kestrel的前置服務器可以獲得額外一些基礎功能。比如通過主機頭的80/443端口轉發、處理生命周期管理和證書管理等。

下圖展示了IIS作為Web前置服務器與運行的ASP.NET Core應用程序的關系:  

ASP.NET Core程序獨立運行在控制台應用程序中,並通過dotnet運行時命令調用。它並沒有被加載到IIS工作進程中,但是IIS卻加載了名為AspNetCoreModule的本地Module,這個Module用於執行外部的控制台程序。

AspNetCoreModule是作為ASP.NET Core Server Hosting Bundle的一部分被安裝在服務器上的。

當安裝ASP.NET核心服務器托管捆綁(或在開發機上安裝.NET Core SDK)時,AspNetCoreModule就會出現在IIS的本地Module列表中:  

AspNetCoreModule作為IIS本地Module,在IIS處理管道周期的最開始就能hook到請求,緊接着就將所有請求重定向到后端的ASP.NET Core程序。這里是所有的請求,也就是說即便是頂級的映射Handler,比如aspx。這些都將從IIS管道中分流到ASP.NET Core中處理。這意味着,沒法簡單的將ASP.NET Core和其他框架放在同一個站點(虛擬目錄)中。這看起來有點退步了,因為在此之前可以混合使用不同框架。

這里IIS站點(虛擬目錄)仍然需要配一個IIS應用程序池,不過這個應用程序池應當使用No Managed Code。這里應用程序池僅僅作為前置代理接受請求,所以它不用實例化.NET運行了。  

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的根目錄。

下面就是web.config的例子: 
 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>
 這里可以看到AspNetCoreModule引用了dotnetexe和.NET Core程序中包含Main方法編譯入口點DLL。

還需要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程序來處理。

當你將ASP.NET Core部署在Windows平台上時,你會希望使用AspNetCoreModule的。

不要把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提供的一些依據HTTP服務的東西,是真正和ASP.NET Core的處理相分離的。但是,即便是這樣,這些特性也不會在調試應用程序上下文時用到。

“運行”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。

打開這個文件夾,可以看到這里面包含了原始的程序結構和所有依賴的nuget程序集。 

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網站發布。

不過,你可以自己創建.pubxml並將其放在項目中\Properties\PublishProfiles文件夾內,這樣就可以欺騙開發工具了。

特定版本的解決方法

很顯然,這個問題在RC2之后的版本會得到更新。所以,當你在一個月后讀到本文的這些步驟時,請先確認下是否可以直接通過Visual Studio界面完成IIS發布。

在ASP.NET Core Web項目中創建“手動概要”:

  • 創建文件夾\Properties\PublishProfiles
  • 創建文件<MyProfile>.pubxml
你可以從非ASP.NET Core項目中拷貝一個已有的.pubxml文件。下面是IIS下的概要文件例子: 
 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>鍵。此鍵非常重要,如果錯誤發布操作將無法執行。如果是從一個現有的文件拷貝過來的,請確保此鍵的設置。

當創建好.pubxml文件后,現在打開Visual Studio的發布對話框,如下所示:  

此時,你就可以將網站發布到遠程服務器上的IIS中,並且可以增量更新內容。

這是目前為止對IIS托管和發布的總結,還沒有文檔描述這些,整個發布過程有些粗糙。顯然微軟知道這件事,也會在ASP.NET Core的RTM版本中修復。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com