前言:
在我們開發一個Web項目的時候,我們需要把項目打包發布到IIS,大概流程是這樣的打包項目放到一個目錄下,IIS管理器添加項目指定打包好的項目路徑等一系列操作,這樣會是不是會讓大家感覺到很煩?這一系列操作給我的感覺肯定是很煩的點來點去,能不能就是說我點一下能能把我想發布的路徑發布出去。答案:能!
在這篇紋章中給大家帶來一個IIS一鍵部署的小工具的實現以及個人的開發思路告訴大家,好了話不多說准備開干!
一、思路:
在本章節中,小編想到的是做成一個配置化發布工具,也就是說通過一個配置文件(json,config)配置好發布的信息,控制台程序運行一下就可以發布出去!
直接上代碼和操作圖:
打開IIS - 應用程序池 - 右鍵一個程序池 - 高級設置



打開了之后是不是又很多參數可以配置應用程序池的信息,每個網站都要對應一個程序池這個步驟很關鍵!
紅色箭頭是表示,可以在類庫中找到對應項的參數配置,方便我們開發!
直接上核心代碼了:
using Microsoft.Web.Administration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using oneKeyDeployment.Common.config;
using oneKeyDeployment.Model;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace oneKeyDeployment.Common
{
/// <summary>
/// 網站發布幫助類
/// </summary>
public class PublishWebHelper
{
/// <summary>
/// 執行一鍵部署(單個網站部署)
/// </summary>
/// <returns></returns>
public static void Execute()
{
//IIS 配置信息
var config = GetIISConfig();
var vDir = config.VDir;
var app = config.Applications;
//程序池配置信息
var poolsConfig = config.ApplicationPools;
var iismanager = CreateServerManager(config);
//創建虛擬目錄
if (vDir != null && vDir.Count() > 0)
{
foreach (var dir in vDir)
{
CreateVDir(config.WebName, dir.DirName, dir.PhysicalPath, iismanager);
}
}
//創建子程序虛擬目錄
foreach (var item in app)
{
foreach (var dir in item.VDir)
{
CreateSubitemVDir(config.WebName, item.Path, dir.DirName, dir.PhysicalPath, iismanager);
}
}
Console.WriteLine("---------------- 程序池 Start ----------------");
//創建程序池
foreach (var item in poolsConfig)
{
CreateApplicationPool(item, iismanager);
}
Console.WriteLine("---------------- 程序池 End ----------------");
//提交保存
CommitChanges(iismanager);
}
/// <summary>
/// 創建應用程序
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
private static ServerManager CreateServerManager(IISConfig config)
{
var ApplicationsConfig = config.Applications;
ServiceController service = ServiceController.GetServices("127.0.0.1").FirstOrDefault(x => x.ServiceName == "W3SVC");
if (service is null)
{
Console.WriteLine("服務器尚未安裝 IIS 服務模塊!");
return null;
}
if (!System.IO.Directory.Exists(config.WebsiteDirectory))
{
Console.WriteLine("指定目錄不存在!");
return null;
}
ServerManager iismanager = new ServerManager();
//判斷web應用程序是否存在
if (iismanager.Sites[config.WebName] != null)
{
///移除應用程序
iismanager.Sites.Remove(iismanager.Sites[config.WebName]);
}
//建立web應用程序(第二個參數為安裝文件的地址)
var site = iismanager.Sites.Add(config.WebName, config.WebsiteDirectory, config.Port);
Console.WriteLine("---------------- 主應用程序 Start ----------------");
Console.WriteLine($"網站名稱:{config.ServerDomainName}");
Console.WriteLine($"端口:{config.Port}");
Console.WriteLine($"服務器域名:{config.ServerDomainName}");
Console.WriteLine($"網站目錄:{config.WebsiteDirectory}");
Console.WriteLine($"程序池名稱:{config.ApplicationPoolName}");
Console.WriteLine("---------------- 主應用程序 End ----------------");
Console.WriteLine("---------------- 子程序 Start ----------------");
//設置子程序 - 應用程序池
foreach (var item in ApplicationsConfig)
{
var application = site.Applications.Add("/" + item.Path, item.PhysicalPath);
application.ApplicationPoolName = item.ApplicationPoolName;
Console.WriteLine("****************************** ↓");
Console.WriteLine($"子程序路徑名稱:/{item.Path}");
Console.WriteLine($"物理路徑:{item.PhysicalPath}");
}
Console.WriteLine("---------------- 子程序 End ----------------");
//設置web網站的應用程序池
var website = iismanager.Sites[config.WebName];
website.Applications["/"].ApplicationPoolName = config.ApplicationPoolName;
if (!string.IsNullOrEmpty(config.ServerDomainName))
{
string str = website.Bindings[0].Host.Split(new char[] { '.' })[0];
string bindingInformation = $"*:{config.Port}:{str}{config.ServerDomainName}";
website.Bindings.Add(bindingInformation, "http");
}
return iismanager;
}
/// <summary>
/// 提交更改
/// </summary>
/// <param name="iismanager"></param>
private static void CommitChanges(ServerManager iismanager)
{
//提交更改
iismanager.CommitChanges();
}
/// <summary>
/// 創建程序池
/// </summary>
/// <param name="pool"></param>
private static void CreateApplicationPool(Model.ApplicationPool poolConfig, ServerManager iismanager)
{
//判斷應用程序池是否存在
if (iismanager.ApplicationPools[poolConfig.Name] != null)
{
//移除應用程序池
iismanager.ApplicationPools.Remove(iismanager.ApplicationPools[poolConfig.Name]);
}
//cpu
var cpuConfig = poolConfig.Cpu;
//回收
var recyclingConfig = poolConfig.Recycling;
//定期重啟
var periodicRestartConfig = poolConfig.Recycling.PeriodicRestart;
//進程孤立
var failureConfig = poolConfig.Failure;
//進程模型
var processModelConfig = poolConfig.ProcessModel;
Microsoft.Web.Administration.ApplicationPool pool = iismanager.ApplicationPools.Add(poolConfig.Name);
pool.Name = poolConfig.Name; // 程序池名字
pool.StartMode = poolConfig.StartMode;//啟動模式
pool.QueueLength = poolConfig.QueueLength;//隊列長度
pool.ManagedRuntimeVersion = poolConfig.ManagedRuntimeVersion;
pool.Enable32BitAppOnWin64 = pool.Enable32BitAppOnWin64;
pool.ManagedPipelineMode = ManagedPipelineMode.Integrated; //托管管道模式
pool.Cpu.Limit = cpuConfig.Limit;//限制最大CPU 50%
pool.Cpu.Action = cpuConfig.Action;//競爭cpu時限制使用最大cpu 百分比
pool.Cpu.ResetInterval = new TimeSpan(00, cpuConfig.ResetInterval, 00); //時隔5分鍾
pool.Cpu.SmpAffinitized = cpuConfig.SmpAffinitized ?? false;
//回收
pool.Recycling.DisallowRotationOnConfigChange = recyclingConfig.DisallowRotationOnConfigChange ?? true; //發生配置更改時禁止回收
pool.Recycling.DisallowOverlappingRotation = recyclingConfig.DisallowOverlappingRotation ?? true;//禁用重疊回收
RecyclingLogEventOnRecycle logEventOnRecycle = RecyclingLogEventOnRecycle.None;
foreach (var item in recyclingConfig.LogEventOnRecycle)
{
logEventOnRecycle = logEventOnRecycle | item;
}
if (recyclingConfig.LogEventOnRecycle != null && recyclingConfig.LogEventOnRecycle.Count() > 0)
pool.Recycling.LogEventOnRecycle = logEventOnRecycle;
foreach (var item in periodicRestartConfig.Schedule)
{
pool.Recycling.PeriodicRestart.Schedule.Add(item);//定時回收資源
}
pool.Recycling.PeriodicRestart.PrivateMemory = periodicRestartConfig.PrivateMemory;
pool.Recycling.PeriodicRestart.Time = new TimeSpan(00, periodicRestartConfig.Time, 00);
pool.Recycling.PeriodicRestart.Requests = periodicRestartConfig.Requests;
pool.Recycling.PeriodicRestart.Memory = periodicRestartConfig.Memory;
//進程孤立
pool.Failure.OrphanActionParams = failureConfig.OrphanActionParams;
pool.Failure.OrphanActionExe = failureConfig.OrphanActionExe;
pool.Failure.OrphanWorkerProcess = failureConfig.OrphanWorkerProcess ?? false;
//模型
pool.ProcessModel.PingInterval = new TimeSpan(00, 00, processModelConfig.PingInterval);
pool.ProcessModel.PingResponseTime = new TimeSpan(00, 00, processModelConfig.PingResponseTime);
pool.ProcessModel.IdentityType = processModelConfig.IdentityType;
pool.ProcessModel.UserName = processModelConfig.UserName;
pool.ProcessModel.Password = processModelConfig.Password;
pool.ProcessModel.ShutdownTimeLimit = new TimeSpan(00, 00, processModelConfig.ShutdownTimeLimit);
pool.ProcessModel.LoadUserProfile = processModelConfig.LoadUserProfile ?? false;
pool.ProcessModel.IdleTimeoutAction = IdleTimeoutAction.Terminate;
pool.ProcessModel.StartupTimeLimit = new TimeSpan(00, 00, processModelConfig.StartupTimeLimit);
pool.ProcessModel.PingingEnabled = processModelConfig.PingingEnabled ?? false;
pool.ProcessModel.LogEventOnProcessModel = processModelConfig.LogEventOnProcessModel;
pool.ProcessModel.IdleTimeout = new TimeSpan(00, processModelConfig.IdleTimeout, 00);
pool.ProcessModel.MaxProcesses = processModelConfig.MaxProcesses;
Console.WriteLine("****************************** ↓");
Console.WriteLine($"程序池名稱:{poolConfig.Name}");
Console.WriteLine($"隊列長度:{poolConfig.QueueLength}");
Console.WriteLine($"啟動模式:{poolConfig.StartMode}");
Console.WriteLine($"啟用32位應用程序:{poolConfig.Enable32BitAppOnWin64}");
Console.WriteLine($"托管管道模式:{poolConfig.ManagedPipelineMode}");
}
/// <summary>
/// 獲取IIS配置
/// </summary>
/// <returns></returns>
private static IISConfig GetIISConfig()
{
var path = System.Environment.CurrentDirectory + Config._IISConfigPath;
using (System.IO.StreamReader file = System.IO.File.OpenText(path))
{
using (JsonTextReader reader = new JsonTextReader(file))
{
var o = (JObject)JToken.ReadFrom(reader);
return o.ToObject<IISConfig>();
}
}
}
/// <summary>
/// 添加虛擬目錄
/// </summary>
/// <param name="siteName">網站名</param>
/// <param name="vDirName">目錄名</param>
/// <param name="physicalPath">對應的文件夾路徑</param>
/// <param name="iismanager"></param>
private static void CreateVDir(string siteName, string vDirName, string physicalPath, ServerManager iismanager)
{
Site site = iismanager.Sites[siteName];
if (site == null)
{
return;
}
site.Applications["/"].VirtualDirectories.Add("/" + vDirName, physicalPath);
}
/// <summary>
/// 添加虛擬目錄
/// </summary>
/// <param name="siteName">網站名</param>
/// <param name="vDirName">目錄名</param>
/// <param name="physicalPath">對應的文件夾路徑</param>
/// <param name="iismanager"></param>
private static void CreateSubitemVDir(string siteName, string subitemSiteName, string vDirName, string physicalPath, ServerManager iismanager)
{
var app = iismanager.Sites[siteName].Applications["/" + subitemSiteName];
if (app == null)
{
return;
}
app.VirtualDirectories.Add("/" + vDirName, physicalPath);
}
}
}
小編用的是json文件配置IIS發布的所以這里上個json的結構給到大家
{
"WebName": "testName", //網站名稱
"Port": 8020, //端口
"ServerDomainName": "", //服務器域名
"WebsiteDirectory": "D:\\IIS\\TLSC.Admin", //網站目錄
"ApplicationPoolName": "File", //程序池名稱
//虛擬目錄沒有就默認[]
"VDir": [],
//子節點
"Applications": [
{
"Path": "File", //路徑名稱
"PhysicalPath": "D:\\IIS\\TLSC.Admin", //物理路徑
"ApplicationPoolName": "File", //程序池名稱
//虛擬目錄沒有就默認[]
"VDir": []
},
{
"Path": "Admin", //路徑名稱
"PhysicalPath": "D:\\IIS\\TLSC.Admin", //物理路徑
"ApplicationPoolName": "Admin", //程序池名稱
//虛擬目錄沒有就默認[]
"VDir": []
}
],
"ApplicationPools": [
{
"ManagedRuntimeVersion": "v4.0", //版本編號
"QueueLength": 1000, //隊列長度
"StartMode": 1, //啟動模式
"Enable32BitAppOnWin64": false, //啟用32位應用程序
"Name": "File", //程序池名稱
"ManagedPipelineMode": 0, //托管管道模式 0 Integrated / 1 Classic
//CPU
"Cpu": {
"Limit": 0, //Limit = 50000 限制最大CPU 50% , 默認為0
"Action": 3, //限制操作 0 NoAction / 1 KillW3wp / 2 Throttle / 3 ThrottleUnderLoad
"ResetInterval": 5, //時間間隔(分鍾)
"SmpAffinitized": false //已啟用處理器關聯
},
//回收
"Recycling": {
"DisallowRotationOnConfigChange": false, //發生配置更改時禁止回收
"DisallowOverlappingRotation": false, //禁用重疊回收
//生成和回收時間日志條目 0 None (所有為false)/ 1 Time / 2 Requests / 4 Schedule / 8 Memory / 16 IsapiUnhealthy / 32 OnDemand/ 64 ConfigChange / 128 PrivateMemory /[] 默認所有true
"LogEventOnRecycle": [ 2, 3, 4, 5 ],
"PeriodicRestart": {
"Time": 50, //固定時間間隔(分鍾)
"Requests": 0, //請求限制 默認為零
"Memory": 0, //虛擬內存限制(KB)
"PrivateMemory": 1024000, //專用內存限制(KB)
//特定時間
"Schedule": [
"03:00:00",
"02:00:00"
]
}
},
//進程孤立
"Failure": {
"OrphanActionExe": "", //可執行文件
"OrphanActionParams": "", //可執行文件參數
"OrphanWorkerProcess": false //已啟用
},
//進程模型
"ProcessModel": {
"PingInterval": 30, //Ping間隔(秒)
"PingResponseTime": 90, //Ping最大響應時間(秒)
"IdentityType": 0, //標識 0 LocalSystem , 1 LocalService , 2 NetworkService, 3 SpecificUser, 4 ApplicationPoolIdentity
"UserName": "", //標識 賬號
"Password": "", //標識 密碼
"ShutdownTimeLimit": 90, //關閉時間限制(秒)
"LoadUserProfile": true, //加載用戶配置文件
"IdleTimeoutAction": 0, //空閑超時操作 0 Terminate / 1 Suspend
"StartupTimeLimit": 90, //啟動時間限制(秒)
"PingingEnabled": true, //啟用 Ping
"LogEventOnProcessModel": 1, //生成進程模型事件日志條目-空閑超時已到
"IdleTimeout": 20, //閑置超時(分鍾)
"MaxProcesses": 1 //最大工作進程數
}
}
]
}
json的文件路徑也是可配置的,在app.config配置讀取json文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<appSettings>
<add key="IISConfigPath" value="..\..\..\json\TempConfig.json" />
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Reflection.TypeExtensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
