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