The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

ASP.NET 如何將檔案寫入到網路芳鄰的分享目錄

我們在使用 Webfarm 架構建置網站時,有許多要注意的地方,我想最麻煩的地方就是如何將使用者上傳的檔案同步到每一台主機!

因為使用者每次 Request 到 Webfarm 的主機時,不一定每次都會連線到同一台 WEB 主機,所以在執行檔案上傳時,一定不能儲存到「本機」路徑,因為你上傳到其中一台,另一台就讀不到。

一般來說會有兩種作法:

1. 將檔案或文件全部都儲存到資料庫中。

2. 將檔案或文件儲存到一個共享的資料夾中。

這種作法是這樣的:

  1. 假設我們有 4 台 WEB 主機,分別命名為 WEB1, WEB2, WEB3, WEB4。 
  2. 共用的檔案統一儲存在 WEB4 主機 (也可以在另一台 File Server )
  3. 其 WEB1 ... WEB4 的 IIS 都設定一組虛擬目錄 Files,並設定對應到 \\WEB4\ShareFolder 分享目錄中,並在 IIS 設定登入到 WEB4 主機的帳號、密碼。
  4. 然後 WEB1 ... WEB4 的 IIS 就可以用 http://WEB4/Files/ 讀取 \\WEB4\ShareFolder 分享目錄中的檔案了!

不過這時問題來了!

由於 ASP.NET 在運行的時候,是採用 ASPNET (IIS5) 或 NETWORK SERVICE (IIS6) 身份在執行的,因此並無權限將檔案讀取或寫入到網路芳鄰的 Share Folder 中。

因為透過 IIS 是可以讀的到檔案的,但是透過 ASP.NET 卻無法正確的取得檔案!使用 System.IO.File.ReadAllText(filename) 讀取檔案內容時,就會發生 Exception !甚至連 File.Exists(filename) 都無法檢查檔案是否存在!

這很有可能會讓 .Net 新手誤以為是 .Net 的 Bug !! 其實 .Net Security 何其重要,希望各位還是抽空多瞭解相關的觀念!

備註:我們常用的 Server.MapPath("~/Files/a.txt") 套用在這種「虛擬目錄」時,會將檔案路徑替換成 \\WEB4\ShareFolder\a.txt

接下來,我分享我個人的 Best Practice,這個環境是建立在沒有 AD 的情況下,如果主機群有建立 AD 環境會簡單很多:

環境說明:

  • 四台 WEB 主機 ( 沒有 AD 環境 )
    • 主機名稱為 WEB1 ... WEB4
  • 一台 File 主機
    • 主機名稱為 File1

1. 新增一個共用的使用者到「 File 主機」與「每一台WEB主機」,每台主機的帳號、密碼都要一樣

帳號:ImpersonateUser
密碼:KesTa8ru

2. 在 File 主機新增分享目錄

分享名稱為 Files

假設實際目錄路徑為 D:\Files

3. 修改目錄權限 ( File 主機 )

D:\Files

ImpersonateUser 可讀取、可寫入(如果需要上傳檔案的話就要開放寫入)

分享目錄權限

ImpersonateUser 可讀取、可寫入(如果需要上傳檔案的話就要開放寫入)

4. 修改目錄權限 ( 所有 WEB 主機 )

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files

ImpersonateUser 可讀取、可寫入

說明: 因為 Web Application 等一下會設定用 ImpersonateUser 的身分執行,這會造成 ASP.NET 無法將動態編譯的程式碼儲存在這個目錄,所以必須修改這個目錄的權限。

Web Application 所在的目錄

ImpersonateUser 可讀取

5. 確認 IIS 的虛擬目錄設定

目錄名稱:Files
目的位址:\\File1\Files
登入帳號:ImpersonateUser
登入密碼:KesTa8ru

6. 修改網站的 web.config

在 <system.web> 底下新增 <identity> 設定,讓網站用 ImpersonateUser 的身份執行!

<identity impersonate="true" userName="ImpersonateUser" password="KesTa8ru" />

只要以上六個步驟就可以完成 Webfarm 的架構設定! 但這只有解決檔案權限的問題而已,還有許多其他的開發細節以後有時間再談。