首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Core 操作 IIS 7+ 完整指南:Microsoft.Web.Administration API 實戰與遷移陷阱

     編輯:ASP.NET 基礎

前言:從 System.DirectoryServices 到 Microsoft.Web.Administration

IIS 7.0 引入全新組態系統 (applicationHost.config + web.config) 與管理 API Microsoft.Web.Administration (MWA),取代舊版 System.DirectoryServices (ADSI) 與 WMI。MWA 提供強型別、交易式提交 (CommitChanges())、遠端管理支援,是 ASP.NET Core 應用程式管理 IIS (建立站點、應用程式、應用程式集區、虛擬目錄、SSL 憑證、URL Rewrite 規則) 的標準方式。

環境準備

  1. NuGet:dotnet add package Microsoft.Web.Administration (版本對應 IIS 版本,10.0.0.0 通用於 IIS 7~10)
  2. 專案檔:<RuntimeIdentifier>win-x64</RuntimeIdentifier> (MWA 需原生 DLL)
  3. 權限:執行身分需為 Administrators 群組成員,或透過 Impersonation / 執行身分為特定服務帳號並授予 IIS 管理權限

核心物件模型

ServerManager (進入點)
  └─ Sites (SiteCollection)
       └─ Site
            ├─ Bindings (BindingCollection) : IP:Port:HostHeader, Protocol, Certificate
            ├─ Applications (ApplicationCollection)
            │    └─ Application
            │         ├─ Path (虛擬路徑 "/app")
            │         ├─ ApplicationPoolName
            │         ├─ VirtualDirectories (VirtualDirectoryCollection)
            │         │    └─ VirtualDirectory : Path, PhysicalPath
            │         └─ ...
            └─ ApplicationDefaults : ApplicationPoolName, EnabledProtocols
  └─ ApplicationPools (ApplicationPoolCollection)
       └─ ApplicationPool
            ├─ Name, ManagedRuntimeVersion (v4.0 / ""), ManagedPipelineMode (Integrated/Classic)
            ├─ ProcessModel : IdentityType, UserName, Password, LoadUserProfile, IdleTimeout
            ├─ Recycling : PeriodicRestart (Time, Requests, Memory, Schedule)
            ├─ Failure : RapidFailProtection, AutoShutdownExe, OrphanActionExe
            └─ CPU : Limit, Action, ResetInterval
  └─ WorkerProcesses (即時進程資訊)
  └─ GetApplicationHostConfiguration() → Configuration (applicationHost.config 完整編輯)

常見操作實作範例

1. 建立網站 (含綁定、應用程式集區、實體路徑)

public void CreateWebsite(string siteName, string physicalPath, string hostHeader, int port = 80, string ip = "*", string appPoolName = null) {
    using var server = new ServerManager();
    
    // 1. 確保/建立應用程式集區
    string poolName = appPoolName ?? $"{siteName}_AppPool";
    if (server.ApplicationPools[poolName] == null) {
        var pool = server.ApplicationPools.Add(poolName);
        pool.ManagedRuntimeVersion = "v4.0";
        pool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
        pool.ProcessModel.IdentityType = ProcessModelIdentityType.ApplicationPoolIdentity;
        pool.Recycling.PeriodicRestart.Time = TimeSpan.FromHours(24);
    }

    // 2. 建立站點
    var site = server.Sites.Add(siteName, "http", $"{ip}:{port}:{hostHeader}", physicalPath);
    site.ApplicationDefaults.ApplicationPoolName = poolName;
    site.ServerAutoStart = true;

    // 3. 可選:新增 HTTPS 綁定 (需憑證指紋)
    // site.Bindings.Add($"{ip}:443:{hostHeader}", certificateHash, "My", SslFlags.Sni);

    server.CommitChanges();
}

2. 建立虛擬目錄 / 應用程式 (子應用程式)

public void CreateVirtualDirectory(string siteName, string virtualPath, string physicalPath, string appPoolName = null) {
    using var server = new ServerManager();
    var site = server.Sites[siteName];
    if (site == null) throw new InvalidOperationException($"站點 {siteName} 不存在");

    var app = site.Applications["/"]; // 根應用程式
    // 或建立子應用程式:site.Applications.Add("/subapp", physicalPath);

    var vdir = app.VirtualDirectories.Add(virtualPath, physicalPath);
    if (!string.IsNullOrEmpty(appPoolName)) app.ApplicationPoolName = appPoolName;

    server.CommitChanges();
}

3. 修改應用程式集區設定 (進階調優)

public void ConfigureAppPool(string poolName, Action configure) {
    using var server = new ServerManager();
    var pool = server.ApplicationPools[poolName] ?? throw new ArgumentException("應用程式集區不存在");
    configure(pool);
    server.CommitChanges();
}

// 使用範例
ConfigureAppPool("MyAppPool", pool => {
    pool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
    pool.ProcessModel.IdleTimeout = TimeSpan.Zero; // 關閉閒置關閉
    pool.ProcessModel.LoadUserProfile = true;      // 載入用戶設定檔 (需註冊表/憑證存取)
    pool.Recycling.PeriodicRestart.Memory = 1024 * 1024; // 1GB 重啟
    pool.Recycling.PeriodicRestart.Requests = 50000;
    pool.CPU.Limit = 80000; // 80% CPU 限制 (1/100000)
    pool.CPU.Action = ProcessorAction.KillW3wp;
});

4. 管理 SSL 憑證綁定 (SNI 支援)

public void AddSslBinding(string siteName, string hostHeader, string certThumbprint, string ip = "*", int port = 443) {
    using var server = new ServerManager();
    var site = server.Sites[siteName];
    var binding = site.Bindings.Add($"{ip}:{port}:{hostHeader}", 
        Convert.FromHexString(certThumbprint.Replace(" ", "")), "My", SslFlags.Sni);
    binding.Protocol = "https";
    server.CommitChanges();
}

5. URL Rewrite 規則程式化管理

public void AddRewriteRule(string siteName, string ruleName, string pattern, string actionType, string actionValue, bool stopProcessing = true) {
    using var server = new ServerManager();
    var config = server.GetApplicationHostConfiguration();
    var section = config.GetSection("system.webServer/rewrite/globalRules", siteName); // 或站點層級
    var rules = section.GetCollection();
    var rule = rules.CreateElement("rule");
    rule["name"] = ruleName;
    rule["stopProcessing"] = stopProcessing;
    var match = rule.GetChildElement("match");
    match["url"] = pattern;
    var action = rule.GetChildElement("action");
    action["type"] = actionType; // Redirect, Rewrite, CustomResponse, AbortRequest
    action["url"] = actionValue;
    rules.Add(rule);
    server.CommitChanges();
}

6. 刪除站點/應用程式/虛擬目錄 (正確順序)

public void DeleteSiteCompletely(string siteName) {
    using var server = new ServerManager();
    var site = server.Sites[siteName];
    if (site == null) return;

    // 1. 停止站點
    site.Stop();
    
    // 2. 移除站點 (會自動移除其應用程式與虛擬目錄)
    server.Sites.Remove(site);
    
    // 3. 可選:移除專用應用程式集區 (若無其他站點使用)
    string poolName = site.ApplicationDefaults.ApplicationPoolName;
    if (server.Sites.All(s => s.ApplicationDefaults.ApplicationPoolName != poolName)) {
        var pool = server.ApplicationPools[poolName];
        if (pool != null) server.ApplicationPools.Remove(pool);
    }
    
    server.CommitChanges();
}

遷移陷阱與最佳實務

陷阱 1:ManagedPipelineMode 選擇

  • Integrated (預設/推薦):ASP.NET Core / ASP.NET 4.5+ / 原生模組管線統一,效能最佳
  • Classic:僅相容舊版 ASP.NET HTTP 模組/處理常式 (system.web/httpModules、httpHandlers),不支援 ASP.NET Core

陷阱 2:ApplicationPoolIdentity vs 自訂帳號

  • ApplicationPoolIdentity (虛擬帳號 IIS AppPool\{Name}):最安全、無密碼管理、自動建立/清理
  • 需存取網路資源 (檔案共用、SQL Windows Auth、AD) 時,建立專用 gMSA (Group Managed Service Account) 或網域帳號,設定 ProcessModel.IdentityType = SpecificUser

陷阱 3:CommitChanges() 交易性

  • 單一 ServerManager 實例內的所有異動會在 CommitChanges() 時以單一交易寫入 applicationHost.config
  • 跨多個 ServerManager 實例的異動非交易性,可能導致組態不一致
  • 最佳實務:單一作業單一 ServerManager 實例,using 區塊確保釋放

陷阱 4:遠端管理

// 連接遠端 IIS (需管理服務啟用、防火牆開放 8172、管理使用者授權)
using var server = ServerManager.OpenRemote("server01.contoso.com");
// 或指定認證
var creds = new NetworkCredential("domain\\admin", "password");
using var server = ServerManager.OpenRemote("server01", creds);

陷阱 5:ASP.NET Core 託管模型差異

  • ASP.NET Core 在 IIS 中以 進程內 (InProcess) 或 進程外 (OutOfProcess) 運行,由 aspNetCore 模組 (ANCM) 代管
  • 應用程式集區 ManagedRuntimeVersion = "" (無 Managed Runtime),ManagedPipelineMode 必為 Integrated
  • 實體路徑指向發布輸出資料夾 (含 web.config、*.dll、*.runtimeconfig.json)

單元測試策略:模擬 ServerManager

public interface IServerManagerFacade : IDisposable {
    SiteCollection Sites { get; }
    ApplicationPoolCollection ApplicationPools { get; }
    void CommitChanges();
    // ... 其他必要成員
}

// 實作包裝真實 ServerManager
public class RealServerManagerFacade : IServerManagerFacade {
    private readonly ServerManager _server = new();
    public SiteCollection Sites => _server.Sites;
    public ApplicationPoolCollection ApplicationPools => _server.ApplicationPools;
    public void CommitChanges() => _server.CommitChanges();
    public void Dispose() => _server.Dispose();
}

// 測試用 In-Memory Fake
public class FakeServerManagerFacade : IServerManagerFacade {
    public SiteCollection Sites { get; } = new FakeSiteCollection();
    public ApplicationPoolCollection ApplicationPools { get; } = new FakeAppPoolCollection();
    public void CommitChanges() { /* 驗證狀態 */ }
    public void Dispose() { }
}

結語

Microsoft.Web.Administration 是 IIS 程式化管理的基石,掌握其物件階層、交易模型、管線模式差異、憑證綁定、遠端管理,能讓部署自動化、藍綠發布、多租戶隔離、基礎設施即代碼 等進階場景落地。建議將常用操作封裝為 冪等的領域服務 (如 IisProvisioningService),配合單元測試與 CI/CD 管線,實現「基礎設施即代碼」的可靠交付。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved