WCF 服务的集合管理器的设计
今天是2019年2月1日,时间过得针对,马上就年底了,当前新年也离我们越来越近了。在此,我也祝福经常浏览我博客的朋友们“新年快乐、阖家欢乐”,来年有一个好彩头。在即将结束这一年之计,写今年的最后一片文章。WCF 我相信大家都使用过,每次宿主该服务的时候都要使用 ServiceHost,如果要加载多个 WCF 服务,那就需要多次 ServiceHost 实例化,而且这个过程大致都是一样的,这就有点太麻烦了。正好现在有时间,也有项目的需要,我就写了一份 WCF 服务的集合管理器,可以加载多个 WCF 服务,也可以对 WCF 的服务进行开启或者关闭的操作,使用起来还是比较方便的。这个设计已经改过多次,现在这个版本是目前最合适、最稳定的版本。 说写就写,OO的三大基本原则,1、面向抽象编程,不要面向实现编程;2、多组合少继承;3、哪里有变化点就封装哪里。 这三大原则我们要死死的记在心里,融化进血液里,由此,我的做法是做接口的抽象设计,代码如下:
1、接口 IWcfServiceManager 的设计如下: 1 /// <summary> 2 /// WCF 服务的实例管理器,该类型可以实现对容器内部的 WCF 服务对象进行增加、删除、查询、开启和关闭的操作。 3 </summary> 4 public interface IWcfServiceManager:IDisposable 5 { 6 7 以指定的名称增加 WCF 服务实例,但是该服务并没有启动。 8 9 <param name="serviceName">表示 WCF 服务的名称。</param> 10 <returns>返回布尔值,true 表示增加 WCF 服务成功,false 表示增加 WCF 失败。</returns> 11 bool AddService(string serviceName); 12 13 14 从容器对象中删除指定名称的 WCF 服务实例。 15 16 17 返回布尔值,true 表示删除 WCF 服务成功,false 表示删除 WCF 服务失败。18 bool RemoveService(19 20 21 获取所有的 WCF 服务实例的集合。 22 23 返回所有的 WCF 服务实例集合。24 IEnumerable<WcfService> GetServices(); 25 26 27 根据指定的名称获取 WCF 服务实例。 28 29 30 返回和指定名称相匹配的 WCF 服务实例,如果不存在则会返回 Null 值。31 WcfService GetService(32 33 34 开启指定名称 WCF 服务实例,此时该服务可以为客户端提供服务了。 35 36 37 返回布尔值,true 表示成功开启 WCF 服务,false 表示开启式 WCF 服务失败。38 bool Start(39 40 41 开启所有的 WCF 服务实例。 42 43 void StartAll(); 44 45 46 关闭指定名称的 WCF 服务实例,此时该服务就不能为客户端提供任何服务了。 47 48 49 返回布尔值,true 表示成功关闭 WCF 服务实例,false 表示关闭 WCF 服务实例失败。50 bool Close(51 52 53 关闭所有的 WCF 服务实例,停止所有的服务。 54 55 CloseAll(); 56 57 58 根据指定的名称来判断该 WCF 服务实例是否已经开启。 59 60 61 返回布尔值,true 表示该名称的 WCF 服务实例是已经开启的,false 表示该名称的 WCF 服务实例是未开启的。62 bool IsStartup(63 64 65 获取 WCF 服务实例的个数 66 67 int Count { get; } 68 } 这个接口的设计就不多说了,很简单,继续我们下一步。 ? 2、实现接口类的设计,类名是:WcfServiceManager.cs 该类型都有详细的备注信息,不用我多说了。 1 2 3 4 abstract class WcfServiceManager : IWcfServiceManager,IDisposable 5 6 #region 私有字段 7 8 private ConcurrentDictionary<string,ServiceHost> _serviceHostGroup; 9 _serviceHostTemp; 10 private [] _assemblyNames; 11 bool _disposed;//是否回收完毕 12 private IList<Assembly> _assemblies; 13 14 #endregion 15 16 #region 构造函数 17 18 19 初始化 WcfServiceManager 类的实例 20 </summary> 21 protected WcfServiceManager() 22 { 23 _serviceHostGroup = new ConcurrentDictionary<(); 24 _serviceHostTemp = (); 25 _assemblies = new List<Assembly> 26 } 27 28 29 30 #region 接口方法的实现 31 32 33 34 35 36 37 serviceName) 38 { 39 if (string.IsNullOrEmpty(serviceName) || .IsNullOrWhiteSpace(serviceName)) 40 { 41 return false; 42 } 43 if (!_serviceHostGroup.ContainsKey(serviceName)) 44 45 Type serviceType = GetServiceTypeFromAssemblies(serviceName,_assemblies); 46 if (serviceType != null) 47 { 48 ServiceHost host = new ServiceHost(serviceType); 49 _serviceHostGroup.TryAdd(serviceName,host); 50 true 51 } 52 else 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 if (_serviceHostGroup.ContainsKey(serviceName)) 72 73 ServiceHost hostInstance = 74 _serviceHostGroup.TryRemove(serviceName,out hostInstance); 75 if (hostInstance != null && hostInstance.State == CommunicationState.Opened) 76 77 hostInstance.Close(); 78 hostInstance = 79 80 81 82 83 84 85 86 87 88 89 public IEnumerable<WcfService> GetServices() 90 91 IList<WcfService> list = new List<WcfService> 92 if (_serviceHostGroup != null && _serviceHostGroup.Count > 0 93 94 foreach (var key in _serviceHostGroup.Keys) 95 96 var service = WcfService(); 97 service.ServiceName = _serviceHostGroup[key].Description.Name; 98 service.State = _serviceHostGroup[key].State; 99 service.Description = _serviceHostGroup[key].Description; 100 list.Add(service); 101 102 103 return list; 104 105 106 107 108 109 110 111 public WcfService GetService(112 113 114 115 throw new ArgumentNullException("要查找的 WCF 服务的名称不能为空!"); 116 117 WcfService service = 118 119 120 service = 121 service.ServiceName = _serviceHostGroup[serviceName].Description.Name; 122 service.State = _serviceHostGroup[serviceName].State; 123 service.Description = _serviceHostGroup[serviceName].Description; 124 service; 125 126 127 128 129 130 清空容器中所有 WCF 服务实例。 131 132 ClearAll() 133 134 135 136 this.CloseAll(); 137 _serviceHostGroup.Clear(); 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 var serviceHost = _serviceHostGroup[serviceName]; 153 if (serviceHost != 154 155 if (serviceHost.State == CommunicationState.Created && serviceHost.State != CommunicationState.Faulted) 156 157 serviceHost.Open(); 158 159 160 else if (serviceHost.State == CommunicationState.Closed || serviceHost.State !=161 162 ServiceHost tempHost; 163 _serviceHostGroup.TryRemove(serviceName,1)"> tempHost); 164 if (tempHost != 165 { 166 if (tempHost.State ==167 { 168 tempHost.Close(); 169 } 170 tempHost = 171 } 172 ServiceHost newhost = ServiceHost(serviceHost.Description.ServiceType); 173 newhost.Open(); 174 175 176 177 178 179 180 181 182 183 184 StartAll() 185 186 187 188 foreach (ServiceHost host _serviceHostGroup.Values) 189 190 if (host.State !=191 192 if (host.State == CommunicationState.Closed) 193 194 ServiceHost newhost = ServiceHost(host.Description.ServiceType); 195 newhost.Open(); 196 _serviceHostTemp.TryAdd(host.Description.ConfigurationName,1)">197 198 199 200 ServiceHost newhost = 201 202 203 204 CommunicationState.Created) 205 206 host.Open(); 207 208 209 210 211 if (_serviceHostTemp != null && _serviceHostTemp.Count > 212 213 foreach (KeyValuePair< _serviceHostTemp) 214 215 (_serviceHostGroup.ContainsKey(item.Key)) 216 217 if (_serviceHostGroup[item.Key].State ==218 219 _serviceHostGroup[item.Key].Close(); 220 221 ServiceHost tempHost; 222 _serviceHostGroup.TryRemove(item.Key,1)">223 if (tempHost.State !=224 225 226 tempHost = 227 228 if (item.Value.State ==229 230 item.Value.Open(); 231 232 _serviceHostGroup.TryAdd(item.Key,item.Value); 233 234 235 _serviceHostTemp.Clear(); 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 var host =251 if (host != 252 253 254 255 host.Close(); 256 257 258 259 260 261 262 263 264 265 CloseAll() 266 267 268 269 270 271 272 273 host.Close(); 274 275 276 277 } 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 重新加载所有的 WCF 服务实例,并将所有的 WCF 服务对象开启 303 304 Reload() 305 306 307 .ClearAll(); 308 .Initialize(); 309 .StartAll(); 310 311 312 313 314 315 int Count 316 317 get 318 319 _serviceHostGroup.Count; 320 321 322 323 324 325 #region 定义的抽象方法 326 327 328 加载所有的 WCF 服务实例对象 329 330 <param name="assemblyFullNames">承载 WCF 服务的应用程序集的完全限定名数组331 void Initialize(params [] assemblyFullNames) 332 333 _assemblyNames = assemblyFullNames; 334 CloseAll(); 335 ClearAll(); 336 337 var currentDomainDlls = GetAssembliesFromCurrentDomain(); 338 var specifiedDlls = GetAssembliesFromSpecifiedCondition(_assemblyNames); 339 var item currentDomainDlls) 340 341 _assemblies.Add(item); 342 343 specifiedDlls) 344 345 346 347 348 Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location); 349 ServiceModelSectionGroup serviceModelGroup = config.GetSectionGroup(system.serviceModel") as ServiceModelSectionGroup; 350 if (serviceModelGroup != 351 352 foreach (ServiceElement service serviceModelGroup.Services.Services) 353 354 .AddService(service.Name); 355 356 357 358 359 360 根据指定的字符串类型的程序集名称列表获取强类型的程序集列表 361 362 返回获取到的强类型的程序集列表363 protected virtual IList<Assembly> GetAssembliesFromSpecifiedCondition([] assemblyNames) 364 365 IList<Assembly> assemblies = 366 if (assemblyNames != null && assemblyNames.Length > 367 368 assemblyNames) 369 370 var assembly = Assembly.Load(item); 371 assemblies.Add(assembly); 372 373 374 assemblies; 375 376 377 378 根据当前的应用程序域获取所有必需的程序集 379 380 返回获取到当前应用程序域内的程序集列表381 virtual IList<Assembly> GetAssembliesFromCurrentDomain() 382 383 IList<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => (!a.FullName.StartsWith(System",StringComparison.OrdinalIgnoreCase) && (!a.FullName.StartsWith(Microsoftmscorlibvshost32SMDiagnostics,StringComparison.OrdinalIgnoreCase)))).ToList(); 384 385 386 387 388 根据 WCF 服务的名称在当前程序域中或者传入的程序集中查找该服务的 Type 类型的对象 389 390 要查找的 WCF 服务的名称391 <param name="assemblies">承载 WCF 服务的程序集列表392 返回WCF服务的Type类型的对象,如果没有找到相应的类型就会返回 Null 值。393 private Type GetServiceTypeFromAssemblies(string serviceName,IList<Assembly> assemblies) 394 395 396 397 398 399 400 if (assemblies == null || assemblies.Count == 401 402 待查找的程序集列表不能为空!403 404 405 try 406 407 if (assemblies != null && assemblies.Count() > 408 409 var currentAssembly = assemblies.FirstOrDefault(a => a.GetType(serviceName) != 410 if (currentAssembly != 411 412 currentAssembly.GetType(serviceName); 413 414 415 416 catch (Exception) 417 418 throw419 420 421 422 423 424 425 #region IDispoable模式 426 427 428 释放托管资源 429 430 Dispose() 431 432 Dispose(433 GC.SuppressFinalize(434 435 436 437 析构函数释放资源 438 439 ~WcfServiceManager() 440 441 Dispose(442 443 444 445 释放所有的托管资源和非托管资源核心方法实现 446 447 <param name="disposing">是否需要释放那些实现IDisposable接口的托管对象448 virtual void Dispose(bool disposing) 449 450 (_disposed) 451 452 return; 如果已经被回收,就中断执行 453 454 (disposing) 455 456 TODO:回收托管资源,调用IDisposable的Dispose()方法就可以 457 458 459 _serviceHostGroup = 460 461 TODO:释放非托管资源,设置对象为null 462 _disposed = 463 464 465 466 } ? 3、真正实现的叶子结点类型设计,类型是:DefaultWcfServiceManager.cs 该类型就是用户将要使用的类型。
sealed DefaultWcfServiceManager:WcfServiceManager,1)"> 6 7 初始化 DefaultWcfServiceManager 类型的实例 public DefaultWcfServiceManager(){ } 13 14 } 主要的类型就差不多了。在这个设计过程中,还会涉及到一个辅助类型?WcfService ? 4、辅助类型?WcfService 的设计编码。很简单,直接上代码。
WCF 服务实例的类型的定义 WcfService 8 _serviceName; 9 private CommunicationState _communicationState; 10 ServiceDescription _serviceDescription; 11 12 13 14 15 初始化 WcfService 类型的实例 18 19 WcfService() 20 { } 21 22 23 24 #region 实例属性 获取或者设置 WCF 服务实例的名称 29 ServiceName 30 31 get { _serviceName; } 32 set 33 34 if ((!string.IsNullOrEmpty(value)) && (!.IsNullOrWhiteSpace(value))) 35 36 _serviceName = value; 37 38 39 40 获取或者设置 WCF 的服务实例的运行状态 43 44 CommunicationState State 45 46 _communicationState; } 47 set { _communicationState = value; } 48 49 50 51 获取或者设置 WCF 服务的描述信息 53 ServiceDescription Description 54 55 _serviceDescription; } 56 57 58 if (value != 59 60 _serviceDescription =61 62 63 64 65 66 } ? 5、单元测试项目代码。 这是最后的代码了,有源码没有测试代码,似乎还少一点。测试代码如下:
1 Program 2 3 static void Main([] args) 4 5 DefaultWcfServiceManager hosts = new DefaultWcfServiceManager("ServiceInstance,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"); 6 DefaultWcfServiceManager hosts = DefaultWcfServiceManager(); 7 hosts.Initialize(ServiceInstance,PublicKeyToken=null 8 hosts.Initialize("ServiceInstance"); 9 string operation = a10 do 11 12 operation = Console.ReadLine(); 13 string.Compare(operation,StartAlltrue) == 14 15 hosts.StartAll(); 16 Console.WriteLine(已经全部打开17 18 19 ConsoleService21 hosts.Close(ServiceInstance.ConsoleService22 Console.WriteLine(ConsoleService 已经关闭23 24 25 ConsoleServiceOpen26 27 hosts.Start(28 Console.WriteLine(ConsoleService 已经打开29 30 31 MathServiceOpen32 33 hosts.Start(ServiceInstance.MathService34 Console.WriteLine(MathService 已经打开36 37 MathService39 hosts.Close(40 Console.WriteLine(MathService 已经关闭41 42 43 CloseAll44 hosts.CloseAll(); 46 Console.WriteLine(已经全部关闭47 48 49 Reload50 51 hosts.Reload(); 52 Console.WriteLine(已经全部重新打开53 54 print55 56 hosts.GetServices()) 58 Console.WriteLine(服务地址:" + item.Description.Endpoints[0].Address.Uri.ToString() + ;状态:" + item.State.ToString()); 60 61 } while (exittrue) != 63 } ? 总结: 好了,就写到这里吧。要想使用 WCF ,必须的命名空间是必须要引入的 System.ServiceModel,当然这里省略了必要的配置数据了,我相信,这个不是很难。也要说明一点,我这个项目是放在类库里面的,WCF 是分为 Client 端和 Server 端的,今天只是贴出了服务器端的代码,如果有需要,在把客户端生成代理类的代码贴出来。年尾了,让不好的东西过去,让自己迎接新的明天,不忘初心,继续努力。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |