Original (原创) by Teddy’s Knowledge Base
(1) WCF Configuration Centralization (WCF配置集中管理)
(2) WCF Automatic Deployment (WCF自动化部署)
(3) WCF Automatic Service Locating (WCF自动化服务定位)
(4) WCF Database Paging & Sorting (WCF数据库分页和排序)
(5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)
(6) 1 + 2 + 3 + 4 + 5 = ?
本文提供一种在WCF服务消费应用程序中通过与服务提供应用程序共享WCF服务契约接口来自动化定位WCF服务实现的方案。
服务定位的意思是服务的消费者给定服务的接口类型,由一个称作服务定位器的对象返回这个服务接口的实现类,这样,服务的消费者对服务的实现类就没有依赖关系。服务定位器这个设计模式的思路诞生于JAVA世界。这个模式又发展成了IoC容器模式。Martin Folwer对这个设计模式已经讨论很多了。
实际上,WCF的ChannelFactory类也实现了服务定位器模式,它提供了一个接受一个端点配置名称的构造函数,通过这个名称,ChannelFactory就能从应用程序配置文件中读取配置信息,构造绑定信息。构造了ChannelFactory实例以后,就能调用它的CreateChannel()方法来创建服务契约的代理了。一个代理其实是一个动态实现的服务契约的实现类或子类。下面是一个使用ChannelFactory的示例:
1 ChannelFactory < IRequestChannel > factory
2
3 = new ChannelFactory < IRequestChannel > ( " MyEndpoint " );
4
5 IRequestChannel proxy = factory.CreateChannel();
6
7 // using proxy instance…
和ServiceHost类类似,ChannelFactory类也提供接受Binding类实例的构造函数。所以,也可以用编程方式构造一个Binding类的实例来构造一个ChannelFactory。
ChannelFactory类有下面这些限制:
要克服这些限制,我们可以考虑对将ChannelFactory类包装成一个安全的WCF服务定位器。这样一个服务定位器的实现要注意下面几点:
下面是一个WCF服务定位器的示例:
1 public sealed class WcfServiceLocator : IServiceLocator
2 {
3 #region Private Members
4
5 // …
6
7 #endregion
8
9 #region Public Methods
10
11 /// <summary>
12 /// Generic version of GetService
13 /// </summary>
14 /// <typeparam name="T"> The service contract type </typeparam>
15 /// <returns> The service proxy instance </returns>
16 public T GetService < T > ()
17 {
18 if ( ! _channelFactories.ContainsKey( typeof (T)))
19 {
20 lock (_channelFactories)
21 {
22 if ( ! _channelFactories.ContainsKey( typeof (T)))
23 {
24 var cf = CreateChannelFactory < T > ();
25 if (cf != null )
26 {
27 _channelFactories.Add( typeof (T), cf);
28 try
29 {
30 _serviceProxies.Add( typeof (T), cf.CreateChannel());
31 }
32 catch
33 {
34 _serviceProxies.Add( typeof (T), null );
35 }
36 }
37 else
38 {
39 _channelFactories.Add( typeof (T), null );
40 _serviceProxies.Add( typeof (T), null );
41 }
42 }
43 }
44 }
45
46 return (T)_serviceProxies[ typeof (T)];
47 }
48
49 #endregion
50
51 #region IDisposable Members
52
53 /// <summary>
54 /// The dispose method,
55 /// closing all created channel factories in this service locator
56 /// </summary>
57 public void Dispose()
58 {
59 Dispose( true );
60 GC.SuppressFinalize( this );
61 }
62
63 private bool disposed;
64
65 private void Dispose( bool disposing)
66 {
67 if (disposed) return ;
68 if (disposing)
69 {
70 foreach (var item in _channelFactories.Values)
71 {
72 if (item != null )
73 {
74 // close channel factory in best practice
75 // refer to: http://bloggingabout.net/blogs/erwyn/archive/2006/12/09/WCF-Service-Proxy-Helper.aspx
76 try
77 {
78 item.Close();
79 }
80 catch (CommunicationException)
81 {
82 item.Abort();
83 }
84 catch (TimeoutException)
85 {
86 item.Abort();
87 }
88 catch (Exception)
89 {
90 item.Abort();
91 throw ;
92 }
93 }
94 }
95 }
96
97 disposed = true ;
98 }
99
100 ~ WcfServiceLocator()
101 {
102 Dispose( false );
103 }
104
105 #endregion
106 }
如果所有的服务全都用WCF服务实现,那么上面这个WCF服务定位器就足够好了。但是,大多数程序同时会使用诸如辅助工具、日志记录、第三方组件包装等等本地服务。这样一来我们就同样需要诸如Unity和Castle IoC容器这样的本地服务定位器。所以,如果我们能够整合WCF服务定位器和第三方的服务定位器,那就更好了。
下面是一个示例的ServiceManager类,它拥有整合第三方服务定位器和上述WCF服务定位器的能力:
1 public interface IServiceLocator : IDisposable
2 {
3 /// <summary>
4 /// Get service
5 /// </summary>
6 /// <param name="serviceContract"> The service contract type </param>
7 /// <returns> The service instance </returns>
8 object GetService(Type serviceContract);
9
10 /// <summary>
11 /// Generic version of GetService
12 /// </summary>
13 /// <typeparam name="T"> The service contract type </typeparam>
14 /// <returns> The service instance </returns>
15 T GetService < T > ();
16 }
17
18 public sealed class ServiceManager
19 {
20 #region Private Singleton
21
22 private static readonly ServiceManager _singleton = new ServiceManager();
23
24 #endregion
25
26 #region Private Constructor
27
28 private readonly Type _externalServiceLocatorType;
29 private readonly List < Type > _cachedExternalServiceTypes = new List < Type > ();
30 private readonly List < Type > _cachedWcfServiceTypes = new List < Type > ();
31
32 private ServiceManager()
33 {
34 var serviceLocatorTypeName = ConfigurationManager.AppSettings[Constants.ExternalServiceLocatorTypeAppSettingName];
35 if ( ! string .IsNullOrEmpty(serviceLocatorTypeName))
36 {
37 var serviceLocatorType = Type.GetType(serviceLocatorTypeName);
38 if (serviceLocatorType != null )
39 {
40 if (serviceLocatorType != typeof (WcfServiceLocator))
41 {
42 _externalServiceLocatorType = serviceLocatorType;
43 }
44 }
45 }
46 }
47
48 #endregion
49
50 #region Public Methods
51
52 /// <summary>
53 /// Get service locator of specified service contract type
54 /// </summary>
55 /// <param name="serviceContract"> The service contract type </param>
56 /// <returns> The service instance </returns>
57 public static IServiceLocator GetServiceLocator(Type serviceContract)
58 {
59 if (serviceContract == null )
60 throw new ArgumentNullException( " serviceContract " );
61
62 if (_singleton._externalServiceLocatorType != null)
63 {
64 if (!_singleton._cachedExternalServiceTypes.Contains(serviceContract))
65 {
66 if (_singleton._cachedWcfServiceTypes.Contains(serviceContract))
67 {
68 return new WcfServiceLocator();
69 }
70 lock (_singleton)
71 {
72 if (!_singleton._cachedExternalServiceTypes.Contains(serviceContract))
73 {
74 if (_singleton._cachedWcfServiceTypes.Contains(serviceContract))
75 {
76 return new WcfServiceLocator();
77 }
78
79 //rethrow the exception in initializing the locator instance directly
80 var locator = (IServiceLocator)Activator.CreateInstance(_singleton._externalServiceLocatorType);
81
82 object service = null;
83 try
84 {
85 service = locator.GetService(serviceContract);
86 if (service != null)
87 {
88 _singleton._cachedExternalServiceTypes.Add(serviceContract);
89 return locator;
90 }
91 }
92 catch
93 {
94 //if could not locate the service
95 _singleton._cachedWcfServiceTypes.Add(serviceContract);
96 return new WcfServiceLocator();
97 }
98 finally
99 {
100 if (service != null)
101 {
102 var disposable = service as IDisposable;
103 if (disposable != null)
104 disposable.Dispose();
105 }
106 }
107 }
108 }
109 }
110 else
111 {
112 var locator = (IServiceLocator)Activator.CreateInstance(_singleton._externalServiceLocatorType);
113 return locator;
114 }
115 }
116
117 _singleton._cachedWcfServiceTypes.Add(serviceContract);
118 return new WcfServiceLocator();
119 }
120
121 /// <summary>
122 /// Get service locator of specified service contract type
123 /// </summary>
124 /// <typeparam name="T"> The service contract type </typeparam>
125 /// <returns></returns>
126 public static IServiceLocator GetServiceLocator < T > ()
127 {
128 return GetServiceLocator( typeof (T));
129 }
130
131 #endregion
132 }
注意:
(1) SOA Design Pattern Catalog: http://www.soapatterns.org/
//我是结尾符,待续…