博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF 服务的集合管理器的设计
阅读量:5167 次
发布时间:2019-06-13

本文共 19052 字,大约阅读时间需要 63 分钟。

    今天是2019年2月1日,时间过得针对,马上就年底了,当前新年也离我们越来越近了。在此,我也祝福经常浏览我博客的朋友们“新年快乐、阖家欢乐”,来年有一个好彩头。在即将结束这一年之计,写今年的最后一片文章。WCF 我相信大家都使用过,每次宿主该服务的时候都要使用 ServiceHost,如果要加载多个 WCF 服务,那就需要多次 ServiceHost 实例化,而且这个过程大致都是一样的,这就有点太麻烦了。正好现在有时间,也有项目的需要,我就写了一份 WCF 服务的集合管理器,可以加载多个 WCF 服务,也可以对 WCF 的服务进行开启或者关闭的操作,使用起来还是比较方便的。这个设计已经改过多次,现在这个版本是目前最合适、最稳定的版本。

    说写就写,OO的三大基本原则,1、面向抽象编程,不要面向实现编程;2、多组合少继承;3、哪里有变化点就封装哪里。

    这三大原则我们要死死的记在心里,融化进血液里,由此,我的做法是做接口的抽象设计,代码如下:

    

    1、接口 IWcfServiceManager 的设计如下:

1     ///  2     /// WCF 服务的实例管理器,该类型可以实现对容器内部的 WCF 服务对象进行增加、删除、查询、开启和关闭的操作。 3     ///  4     public interface IWcfServiceManager:IDisposable 5     { 6         ///  7         /// 以指定的名称增加 WCF 服务实例,但是该服务并没有启动。 8         ///  9         /// 表示 WCF 服务的名称。10         /// 
返回布尔值,true 表示增加 WCF 服务成功,false 表示增加 WCF 失败。
11 bool AddService(string serviceName);12 13 /// 14 /// 从容器对象中删除指定名称的 WCF 服务实例。15 /// 16 /// 表示 WCF 服务的名称。17 ///
返回布尔值,true 表示删除 WCF 服务成功,false 表示删除 WCF 服务失败。
18 bool RemoveService(string serviceName);19 20 /// 21 /// 获取所有的 WCF 服务实例的集合。22 /// 23 ///
返回所有的 WCF 服务实例集合。
24 IEnumerable
GetServices();25 26 ///
27 /// 根据指定的名称获取 WCF 服务实例。28 /// 29 ///
表示 WCF 服务的名称。30 ///
返回和指定名称相匹配的 WCF 服务实例,如果不存在则会返回 Null 值。
31 WcfService GetService(string serviceName);32 33 ///
34 /// 开启指定名称 WCF 服务实例,此时该服务可以为客户端提供服务了。35 /// 36 ///
表示 WCF 服务的名称。37 ///
返回布尔值,true 表示成功开启 WCF 服务,false 表示开启式 WCF 服务失败。
38 bool Start(string serviceName);39 40 ///
41 /// 开启所有的 WCF 服务实例。42 /// 43 void StartAll();44 45 ///
46 /// 关闭指定名称的 WCF 服务实例,此时该服务就不能为客户端提供任何服务了。47 /// 48 ///
表示 WCF 服务的名称。49 ///
返回布尔值,true 表示成功关闭 WCF 服务实例,false 表示关闭 WCF 服务实例失败。
50 bool Close(string serviceName);51 52 ///
53 /// 关闭所有的 WCF 服务实例,停止所有的服务。54 /// 55 void CloseAll(); 56 57 ///
58 /// 根据指定的名称来判断该 WCF 服务实例是否已经开启。59 /// 60 ///
表示 WCF 服务的名称。61 ///
返回布尔值,true 表示该名称的 WCF 服务实例是已经开启的,false 表示该名称的 WCF 服务实例是未开启的。
62 bool IsStartup(string serviceName);63 64 ///
65 /// 获取 WCF 服务实例的个数66 /// 67 int Count { get; }68 }

        这个接口的设计就不多说了,很简单,继续我们下一步。

 

    2、实现接口类的设计,类名是:WcfServiceManager.cs

      该类型都有详细的备注信息,不用我多说了。

1     ///   2     /// WCF 服务的实例管理器,该类型可以实现对容器内部的 WCF 服务对象进行增加、删除、查询、开启和关闭的操作。  3     ///   4     public abstract class WcfServiceManager : IWcfServiceManager, IDisposable  5     {  6         #region 私有字段  7   8         private ConcurrentDictionary
_serviceHostGroup; 9 private ConcurrentDictionary
_serviceHostTemp; 10 private string[] _assemblyNames; 11 private bool _disposed;//是否回收完毕 12 private IList
_assemblies; 13 14 #endregion 15 16 #region 构造函数 17 18 ///
19 /// 初始化 WcfServiceManager 类的实例 20 /// 21 protected WcfServiceManager() 22 { 23 _serviceHostGroup = new ConcurrentDictionary
(); 24 _serviceHostTemp = new ConcurrentDictionary
(); 25 _assemblies = new List
(); 26 } 27 28 #endregion 29 30 #region 接口方法的实现 31 32 ///
33 /// 以指定的名称增加 WCF 服务实例,但是该服务并没有启动。 34 /// 35 ///
表示 WCF 服务的名称。 36 ///
返回布尔值,true 表示增加 WCF 服务成功,false 表示增加 WCF 失败。
37 public bool AddService(string serviceName) 38 { 39 if (string.IsNullOrEmpty(serviceName) || string.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 return true; 51 } 52 else 53 { 54 return false; 55 } 56 } 57 return false; 58 } 59 60 ///
61 /// 从容器对象中删除指定名称的 WCF 服务实例。 62 /// 63 ///
表示 WCF 服务的名称。 64 ///
返回布尔值,true 表示删除 WCF 服务成功,false 表示删除 WCF 服务失败。
65 public bool RemoveService(string serviceName) 66 { 67 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName)) 68 { 69 return false; 70 } 71 if (_serviceHostGroup.ContainsKey(serviceName)) 72 { 73 ServiceHost hostInstance = null; 74 _serviceHostGroup.TryRemove(serviceName, out hostInstance); 75 if (hostInstance != null && hostInstance.State == CommunicationState.Opened) 76 { 77 hostInstance.Close(); 78 hostInstance = null; 79 } 80 return true; 81 } 82 return false; 83 } 84 85 ///
86 /// 获取所有的 WCF 服务实例的集合。 87 /// 88 ///
返回所有的 WCF 服务实例集合。
89 public IEnumerable
GetServices() 90 { 91 IList
list = new List
(); 92 if (_serviceHostGroup != null && _serviceHostGroup.Count > 0) 93 { 94 foreach (var key in _serviceHostGroup.Keys) 95 { 96 var service = new 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 /// 根据指定的名称获取 WCF 服务实例。108 /// 109 ///
表示 WCF 服务的名称。110 ///
返回和指定名称相匹配的 WCF 服务实例,如果不存在则会返回 Null 值。
111 public WcfService GetService(string serviceName)112 {113 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))114 {115 throw new ArgumentNullException("要查找的 WCF 服务的名称不能为空!");116 }117 WcfService service = null;118 if (_serviceHostGroup.ContainsKey(serviceName))119 {120 service = new WcfService();121 service.ServiceName = _serviceHostGroup[serviceName].Description.Name;122 service.State = _serviceHostGroup[serviceName].State;123 service.Description = _serviceHostGroup[serviceName].Description;124 return service;125 }126 return service;127 }128 129 ///
130 /// 清空容器中所有 WCF 服务实例。131 /// 132 public void ClearAll()133 {134 if (_serviceHostGroup != null && _serviceHostGroup.Count > 0)135 {136 this.CloseAll();137 _serviceHostGroup.Clear();138 }139 }140 141 ///
142 /// 开启指定名称 WCF 服务实例,此时该服务可以为客户端提供服务了。143 /// 144 ///
表示 WCF 服务的名称。145 ///
返回布尔值,true 表示成功开启 WCF 服务,false 表示开启式 WCF 服务失败。
146 public bool Start(string serviceName)147 {148 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))149 {150 return false;151 }152 var serviceHost = _serviceHostGroup[serviceName];153 if (serviceHost != null)154 {155 if (serviceHost.State == CommunicationState.Created && serviceHost.State != CommunicationState.Faulted)156 {157 serviceHost.Open();158 return true;159 }160 else if (serviceHost.State == CommunicationState.Closed || serviceHost.State != CommunicationState.Faulted)161 {162 ServiceHost tempHost; 163 _serviceHostGroup.TryRemove(serviceName,out tempHost);164 if (tempHost != null)165 {166 if (tempHost.State == CommunicationState.Opened)167 {168 tempHost.Close();169 }170 tempHost = null;171 }172 ServiceHost newhost = new ServiceHost(serviceHost.Description.ServiceType);173 newhost.Open();174 _serviceHostGroup.TryAdd(serviceName, newhost);175 return true;176 }177 }178 return false;179 }180 181 ///
182 /// 开启所有的 WCF 服务实例。183 /// 184 public void StartAll()185 {186 if (_serviceHostGroup != null && _serviceHostGroup.Count > 0)187 {188 foreach (ServiceHost host in _serviceHostGroup.Values)189 {190 if (host.State != CommunicationState.Opened)191 {192 if (host.State == CommunicationState.Closed)193 {194 ServiceHost newhost = new ServiceHost(host.Description.ServiceType);195 newhost.Open();196 _serviceHostTemp.TryAdd(host.Description.ConfigurationName, newhost);197 }198 else if (host.State == CommunicationState.Faulted)199 {200 ServiceHost newhost = new ServiceHost(host.Description.ServiceType);201 newhost.Open();202 _serviceHostTemp.TryAdd(host.Description.ConfigurationName, newhost);203 }204 else if (host.State == CommunicationState.Created)205 {206 host.Open();207 }208 }209 }210 }211 if (_serviceHostTemp != null && _serviceHostTemp.Count > 0)212 {213 foreach (KeyValuePair
item in _serviceHostTemp)214 {215 if (_serviceHostGroup.ContainsKey(item.Key))216 {217 if (_serviceHostGroup[item.Key].State == CommunicationState.Opened)218 {219 _serviceHostGroup[item.Key].Close();220 }221 ServiceHost tempHost;222 _serviceHostGroup.TryRemove(item.Key,out tempHost);223 if (tempHost.State != CommunicationState.Closed)224 {225 tempHost.Close();226 tempHost = null;227 }228 if (item.Value.State == CommunicationState.Closed)229 {230 item.Value.Open();231 }232 _serviceHostGroup.TryAdd(item.Key, item.Value);233 }234 }235 _serviceHostTemp.Clear();236 }237 }238 239 ///
240 /// 关闭指定名称的 WCF 服务实例,此时该服务就不能为客户端提供任何服务了。241 /// 242 ///
表示 WCF 服务的名称。243 ///
返回布尔值,true 表示成功关闭 WCF 服务实例,false 表示关闭 WCF 服务实例失败。
244 public bool Close(string serviceName)245 {246 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))247 {248 return false;249 }250 var host = _serviceHostGroup[serviceName];251 if (host != null)252 {253 if (host.State == CommunicationState.Opened)254 {255 host.Close(); 256 }257 return true;258 }259 return false;260 }261 262 ///
263 /// 关闭所有的 WCF 服务实例,停止所有的服务。264 /// 265 public void CloseAll()266 {267 if (_serviceHostGroup != null && _serviceHostGroup.Count > 0)268 {269 foreach (ServiceHost host in _serviceHostGroup.Values)270 {271 if (host.State == CommunicationState.Opened)272 {273 host.Close();274 }275 }276 }277 } 278 279 ///
280 /// 根据指定的名称来判断该 WCF 服务实例是否已经开启。281 /// 282 ///
表示 WCF 服务的名称。283 ///
返回布尔值,true 表示该名称的 WCF 服务实例是已经开启的,false 表示该名称的 WCF 服务实例是未开启的。
284 public bool IsStartup(string serviceName)285 {286 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))287 {288 return false;289 }290 var host = _serviceHostGroup[serviceName];291 if (host != null)292 {293 if (host.State == CommunicationState.Opened)294 {295 return true;296 }297 }298 return false;299 }300 301 ///
302 /// 重新加载所有的 WCF 服务实例,并将所有的 WCF 服务对象开启303 /// 304 public void Reload()305 {306 this.CloseAll();307 this.ClearAll();308 this.Initialize();309 this.StartAll();310 }311 312 ///
313 /// 获取 WCF 服务实例的个数314 /// 315 public int Count316 {317 get318 {319 return _serviceHostGroup.Count;320 }321 }322 323 #endregion324 325 #region 定义的抽象方法326 327 ///
328 /// 加载所有的 WCF 服务实例对象329 /// 330 ///
承载 WCF 服务的应用程序集的完全限定名数组331 public void Initialize(params string[] assemblyFullNames)332 {333 _assemblyNames = assemblyFullNames;334 CloseAll();335 ClearAll();336 337 var currentDomainDlls = GetAssembliesFromCurrentDomain();338 var specifiedDlls = GetAssembliesFromSpecifiedCondition(_assemblyNames);339 foreach (var item in currentDomainDlls)340 {341 _assemblies.Add(item);342 }343 foreach (var item in specifiedDlls)344 {345 _assemblies.Add(item);346 }347 348 Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);349 ServiceModelSectionGroup serviceModelGroup = config.GetSectionGroup("system.serviceModel") as ServiceModelSectionGroup;350 if (serviceModelGroup != null)351 {352 foreach (ServiceElement service in serviceModelGroup.Services.Services)353 {354 this.AddService(service.Name);355 }356 }357 }358 359 ///
360 /// 根据指定的字符串类型的程序集名称列表获取强类型的程序集列表361 /// 362 ///
返回获取到的强类型的程序集列表
363 protected virtual IList
GetAssembliesFromSpecifiedCondition(params string[] assemblyNames)364 {365 IList
assemblies = new List
();366 if (assemblyNames != null && assemblyNames.Length > 0)367 {368 foreach (var item in assemblyNames)369 {370 var assembly = Assembly.Load(item);371 assemblies.Add(assembly);372 }373 }374 return assemblies;375 }376 377 ///
378 /// 根据当前的应用程序域获取所有必需的程序集379 /// 380 ///
返回获取到当前应用程序域内的程序集列表
381 protected virtual IList
GetAssembliesFromCurrentDomain()382 {383 IList
assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => (!a.FullName.StartsWith("System", StringComparison.OrdinalIgnoreCase) && (!a.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) && (!a.FullName.StartsWith("mscorlib", StringComparison.OrdinalIgnoreCase)) && (!a.FullName.StartsWith("vshost32", StringComparison.OrdinalIgnoreCase)) && (!a.FullName.StartsWith("SMDiagnostics", StringComparison.OrdinalIgnoreCase)))).ToList();384 return assemblies;385 }386 387 ///
388 /// 根据 WCF 服务的名称在当前程序域中或者传入的程序集中查找该服务的 Type 类型的对象389 /// 390 ///
要查找的 WCF 服务的名称391 ///
承载 WCF 服务的程序集列表392 ///
返回WCF服务的Type类型的对象,如果没有找到相应的类型就会返回 Null 值。
393 private Type GetServiceTypeFromAssemblies(string serviceName, IList
assemblies)394 {395 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))396 {397 throw new ArgumentNullException("要查找的 WCF 服务的名称");398 }399 400 if (assemblies == null || assemblies.Count == 0)401 {402 throw new ArgumentNullException("待查找的程序集列表不能为空!");403 }404 405 try406 {407 if (assemblies != null && assemblies.Count() > 0)408 {409 var currentAssembly = assemblies.FirstOrDefault(a => a.GetType(serviceName) != null);410 if (currentAssembly != null)411 {412 return currentAssembly.GetType(serviceName);413 }414 }415 }416 catch (Exception)417 {418 throw;419 }420 return null;421 }422 423 #endregion424 425 #region IDispoable模式426 427 ///
428 /// 释放托管资源429 /// 430 public void Dispose()431 {432 Dispose(true);433 GC.SuppressFinalize(this);434 }435 436 ///
437 /// 析构函数释放资源438 /// 439 ~WcfServiceManager()440 {441 Dispose(false);442 }443 444 ///
445 /// 释放所有的托管资源和非托管资源核心方法实现446 /// 447 ///
是否需要释放那些实现IDisposable接口的托管对象448 protected virtual void Dispose(bool disposing)449 {450 if (_disposed)451 {452 return; //如果已经被回收,就中断执行453 }454 if (disposing)455 {456 //TODO:回收托管资源,调用IDisposable的Dispose()方法就可以457 this.CloseAll();458 this.ClearAll();459 _serviceHostGroup = null;460 }461 //TODO:释放非托管资源,设置对象为null462 _disposed = true;463 }464 465 #endregion466 }

 

    3、真正实现的叶子结点类型设计,类型是:DefaultWcfServiceManager.cs

        该类型就是用户将要使用的类型。

        

1     ///  2     /// WCF 服务的实例管理器,该类型可以实现对容器内部的 WCF 服务对象进行增加、删除、查询、开启和关闭的操作。 3     ///  4     public sealed class DefaultWcfServiceManager:WcfServiceManager, IDisposable 5     { 6         #region 构造函数 7  8         ///  9         /// 初始化 DefaultWcfServiceManager 类型的实例10         /// 11         public DefaultWcfServiceManager(){ }12 13         #endregion14     }

      主要的类型就差不多了。在这个设计过程中,还会涉及到一个辅助类型 WcfService

 

    4、辅助类型 WcfService 的设计编码。很简单,直接上代码。

      

1     ///  2     /// WCF 服务实例的类型的定义 3     ///  4     public sealed class WcfService 5     { 6         #region 私有字段 7  8         private string _serviceName; 9         private CommunicationState _communicationState;10         private ServiceDescription _serviceDescription;11 12         #endregion13 14         #region 构造函数15 16         /// 17         /// 初始化 WcfService 类型的实例18         /// 19         public WcfService()20         { }21 22         #endregion23 24         #region 实例属性25 26         /// 27         /// 获取或者设置 WCF 服务实例的名称28         /// 29         public string ServiceName30         {31             get { return _serviceName; }32             set33             {34                 if ((!string.IsNullOrEmpty(value)) && (!string.IsNullOrWhiteSpace(value)))35                 {36                     _serviceName = value;37                 }38             }39         }40 41         /// 42         /// 获取或者设置 WCF 的服务实例的运行状态43         /// 44         public CommunicationState State45         {46             get { return _communicationState; }47             set { _communicationState = value; }48         }49         50         /// 51         /// 获取或者设置 WCF 服务的描述信息52         /// 53         public ServiceDescription Description54         {55             get { return _serviceDescription; }56             set57             {58                 if (value != null)59                 {60                     _serviceDescription = value;61                 }62             }63         }64 65         #endregion66     }

 

    5、单元测试项目代码。

        这是最后的代码了,有源码没有测试代码,似乎还少一点。测试代码如下:

        

1     class Program 2     { 3         static void Main(string[] args) 4         { 5             //DefaultWcfServiceManager hosts = new DefaultWcfServiceManager("ServiceInstance, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 6             DefaultWcfServiceManager hosts = new DefaultWcfServiceManager(); 7             hosts.Initialize("ServiceInstance, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 8             //hosts.Initialize("ServiceInstance"); 9             string operation = "a";10             do11             {12                 operation = Console.ReadLine();13                 if (string.Compare(operation, "StartAll", true) == 0)14                 {15                     hosts.StartAll();16                     Console.WriteLine("已经全部打开");17                 }18 19                 if (string.Compare(operation, "ConsoleService", true) == 0)20                 {21                     hosts.Close("ServiceInstance.ConsoleService");22                     Console.WriteLine("ConsoleService 已经关闭");23                 }24 25                 if (string.Compare(operation, "ConsoleServiceOpen", true) == 0)26                 {27                     hosts.Start("ServiceInstance.ConsoleService");28                     Console.WriteLine("ConsoleService 已经打开");29                 }30 31                 if (string.Compare(operation, "MathServiceOpen", true) == 0)32                 {33                     hosts.Start("ServiceInstance.MathService");34                     Console.WriteLine("MathService 已经打开");35                 }36 37                 if (string.Compare(operation, "MathService", true) == 0)38                 {39                     hosts.Close("ServiceInstance.MathService");40                     Console.WriteLine("MathService 已经关闭");41                 }42 43                 if (string.Compare(operation, "CloseAll", true) == 0)44                 {45                     hosts.CloseAll();46                     Console.WriteLine("已经全部关闭");47                 }48 49                 if (string.Compare(operation, "Reload", true) == 0)50                 {51                     hosts.Reload();52                     Console.WriteLine("已经全部重新打开");53                 }54                 if (string.Compare(operation, "print", true) == 0)55                 {56                     foreach (var item in hosts.GetServices())57                     {58                         Console.WriteLine("服务地址:" + item.Description.Endpoints[0].Address.Uri.ToString() + ";状态:" + item.State.ToString());59                     }60                 }61             } while (string.Compare(operation, "exit", true) != 0);62         }63     }

 

    总结:

      好了,就写到这里吧。要想使用 WCF ,必须的命名空间是必须要引入的 System.ServiceModel,当然这里省略了必要的配置数据了,我相信,这个不是很难。也要说明一点,我这个项目是放在类库里面的,WCF 是分为 Client 端和 Server 端的,今天只是贴出了服务器端的代码,如果有需要,在把客户端生成代理类的代码贴出来。年尾了,让不好的东西过去,让自己迎接新的明天,不忘初心,继续努力。

转载于:https://www.cnblogs.com/PatrickLiu/p/10346046.html

你可能感兴趣的文章
Ubuntu下关闭防火墙
查看>>
TCP/IP 邮件的原理
查看>>
原型设计工具
查看>>
windows下的C++ socket服务器(4)
查看>>
css3 2d转换3d转换以及动画的知识点汇总
查看>>
【Java】使用Eclipse进行远程调试,Linux下开启远程调试
查看>>
对Vue为什么不支持IE8的解释之一
查看>>
计算机改名导致数据库链接的诡异问题
查看>>
Java8内存模型—永久代(PermGen)和元空间(Metaspace)(转)
查看>>
ObjectiveC基础教程(第2版)
查看>>
centos 引导盘
查看>>
Notes of Daily Scrum Meeting(12.8)
查看>>
Apriori算法
查看>>
onlevelwasloaded的调用时机
查看>>
lr_start_transaction/lr_end_transaction事物组合
查看>>
CodeIgniter学习笔记(四)——CI超级对象中的load装载器
查看>>
.NET CLR基本术语
查看>>
ubuntu的home目录下,Desktop等目录消失不见
查看>>
建立,查询二叉树 hdu 5444
查看>>
[Spring框架]Spring 事务管理基础入门总结.
查看>>