WCF 服务的集合管理器的设计

    今天是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<string, ServiceHost> _serviceHostGroup;
  9         private ConcurrentDictionary<string, ServiceHost> _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<string, ServiceHost>();
 24             _serviceHostTemp = new ConcurrentDictionary<string, ServiceHost>();            
 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<string, ServiceHost> 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 Count
316         {
317             get
318             {
319                 return _serviceHostGroup.Count;
320             }
321         }
322 
323         #endregion
324 
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             try
406             {
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         #endregion
424 
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:释放非托管资源,设置对象为null
462             _disposed = true;
463         }
464 
465         #endregion
466     }

 

    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         #endregion
14     }

      主要的类型就差不多了。在这个设计过程中,还会涉及到一个辅助类型 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         #endregion
13 
14         #region 构造函数
15 
16         /// 
17         /// 初始化 WcfService 类型的实例
18         /// 
19         public WcfService()
20         { }
21 
22         #endregion
23 
24         #region 实例属性
25 
26         /// 
27         /// 获取或者设置 WCF 服务实例的名称
28         /// 
29         public string ServiceName
30         {
31             get { return _serviceName; }
32             set
33             {
34                 if ((!string.IsNullOrEmpty(value)) && (!string.IsNullOrWhiteSpace(value)))
35                 {
36                     _serviceName = value;
37                 }
38             }
39         }
40 
41         /// 
42         /// 获取或者设置 WCF 的服务实例的运行状态
43         /// 
44         public CommunicationState State
45         {
46             get { return _communicationState; }
47             set { _communicationState = value; }
48         }
49         
50         /// 
51         /// 获取或者设置 WCF 服务的描述信息
52         /// 
53         public ServiceDescription Description
54         {
55             get { return _serviceDescription; }
56             set
57             {
58                 if (value != null)
59                 {
60                     _serviceDescription = value;
61                 }
62             }
63         }
64 
65         #endregion
66     }

 

    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             do
11             {
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 端的,今天只是贴出了服务器端的代码,如果有需要,在把客户端生成代理类的代码贴出来。年尾了,让不好的东西过去,让自己迎接新的明天,不忘初心,继续努力。

你可能感兴趣的:(WCF 服务的集合管理器的设计)