using Microsoft.Web.Administration; using Newtonsoft.Json; using Newtonsoft.Json.Linq; 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; using System.Xml.Linq; namespace OneClickPublishWeb { /// /// 网站发布帮助类 /// public class PublishWebHelper { /// /// 执行一键部署(单个网站部署) /// /// public static void Execute() { //IIS 配置信息 var configs = GetIISConfigs(); foreach (var config in configs.MainApplications) { 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); } } if (app!=null) { //创建子程序虚拟目录 foreach (var item in app) { if (item.VDir!=null) { 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); } } /// /// 创建应用程序 /// /// /// private static ServerManager CreateServerManager(MainApplication config) { var ApplicationsConfig = config; 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应用程序(第二个参数为安装文件的地址) Site site = default; if (config.IsCertificate) { site = AddHostHeaderSSL(iismanager, config.WebName, config.Port, "", config.PhysicalPath); } else { 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 ----------------"); //设置子程序 - 应用程序池 if (ApplicationsConfig.Applications!=null) { foreach (var item in ApplicationsConfig.Applications) { 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; } /// /// 提交更改 /// /// private static void CommitChanges(ServerManager iismanager) { //提交更改 iismanager.CommitChanges(); } /// /// 创建程序池 /// /// private static void CreateApplicationPool(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}"); } /// /// 获取IIS配置 /// /// private static IISConfig GetIISConfigs() { var path = Path.GetFullPath("./cfg/config.json"); using (System.IO.StreamReader file = System.IO.File.OpenText(path)) { using (JsonTextReader reader = new JsonTextReader(file)) { var o = (JObject)JToken.ReadFrom(reader); var iis = o.ToObject(); return iis; } } } /// /// 添加虚拟目录 /// /// 网站名 /// 目录名 /// 对应的文件夹路径 /// 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); } /// /// 添加虚拟目录 /// /// 网站名 /// 目录名 /// 对应的文件夹路径 /// 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); } // /// 增加绑定域名(ssl) /// /// 站点名称 /// 端口 /// 绑定域名 public static Site AddHostHeaderSSL(ServerManager iismanager, string webName, int port, string bindingDomainName, string physicalPath) { //**pfxPath**是指提供给你的.pfx文件的路径,购买ssl之后他会提供给你相关的文件,里面有多个文件 //一般包含apache文件夹,iis文件夹,nginx文件夹,我使用的是iis部署,所以.pfx文件在iis文件夹里面 //**certPwd**是指购买ssl之后提供给你的秘钥 string pfx = "./cfg/isas.pfx"; var store = new X509Store(StoreName.AuthRoot, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); var certificate = new X509Certificate2(pfx, "123456", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); store.Add(certificate); store.Close(); var certificateStoreName = store.Name; //绑定的证书名称 var certificateHash = certificate.GetCertHash(); //证书内容 string bindingInformation = "*:" + port + ":" + bindingDomainName; Site site = iismanager.Sites.Add(webName,bindingInformation, physicalPath, certificateHash, certificateStoreName); return site; } } }