C# IIS一键部署(微软类库)

前言:

  在我们开发一个Web项目的时候,我们需要把项目打包发布到IIS,大概流程是这样的打包项目放到一个目录下,IIS管理器添加项目指定打包好的项目路径等一系列操作,这样会是不是会让大家感觉到很烦?这一系列操作给我的感觉肯定是很烦的点来点去,能不能就是说我点一下能能把我想发布的路径发布出去。答案:能!

  在这篇纹章中给大家带来一个IIS一键部署的小工具的实现以及个人的开发思路告诉大家,好了话不多说准备开干!

 

一、思路:

  在本章节中,小编想到的是做成一个配置化发布工具,也就是说通过一个配置文件(json,config)配置好发布的信息,控制台程序运行一下就可以发布出去!

 

直接上代码和操作图:

打开IIS - 应用程序池 - 右键一个程序池 - 高级设置


打开了之后是不是又很多参数可以配置应用程序池的信息,每个网站都要对应一个程序池这个步骤很关键!

红色箭头是表示,可以在类库中找到对应项的参数配置,方便我们开发!

直接上核心代码了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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的结构给到大家

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{
  "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文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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>

源码链接:https://gitee.com/Ramon-Zeng/oneKeyDeployment

posted @   糯米雪梨  阅读(1409)  评论(1编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示