SOMS/test/Web一键发布IIS/PublishWebHelper.cs
2024-07-15 10:31:26 +08:00

325 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}