123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- 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
- {
- /// <summary>
- /// 网站发布帮助类
- /// </summary>
- public class PublishWebHelper
- {
- /// <summary>
- /// 执行一键部署(单个网站部署)
- /// </summary>
- /// <returns></returns>
- 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);
- }
-
- }
- /// <summary>
- /// 创建应用程序
- /// </summary>
- /// <param name="config"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 提交更改
- /// </summary>
- /// <param name="iismanager"></param>
- private static void CommitChanges(ServerManager iismanager)
- {
- //提交更改
- iismanager.CommitChanges();
- }
- /// <summary>
- /// 创建程序池
- /// </summary>
- /// <param name="pool"></param>
- 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}");
- }
- /// <summary>
- /// 获取IIS配置
- /// </summary>
- /// <returns></returns>
- 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<IISConfig>();
-
- return iis;
- }
- }
- }
- /// <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);
- }
- // <summary>
- /// 增加绑定域名(ssl)
- /// </summary>
- /// <param name="webName">站点名称</param>
- /// <param name="port">端口</param>
- /// <param name="bindingDomainName">绑定域名</param>
- 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;
- }
- }
- }
|