C# IIS一键部署(微软类库)
前言:
在我们开发一个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>