我們在之前的博客已經完成過實例,大家也看到了如何使用WCF服務:
添加服務引用——>輸入服務地址——>實例化服務——>調用服務方法
那麼今天為什麼要再次說“程序中WCF服務整合”這個話題?
用過WebService的人都知道,隨著服務的增多,管理WebService是一個非常繁重的工作。好了,今天我們的目標來了——讓WCF服務變得整齊、有序、易管理!
首先,我們建立一個工廠類,這個工廠用來實例化我們的服務。這樣做的好處是,所有的服務都是由工廠實例化的。
然後我們要建立一個公共的接口,這個接口繼承所有的服務接口。這樣做的好處是,所有的服務接口都可以用這個接口來代替。
好了,有了這兩點,我們就可以利用多態+工廠來統一管理我們的服務了。
說了這麼多理論,還是以我們程序猿的語言說更明了一些!
1、建立接口類IServices
namespace Modules.Interface { [ServiceContract] public interface IServices : IUserSevice { } }
2、建立服務工廠ServiceFactory
namespace Modules.Factory { public class ServiceFactory { private static readonly SortedList_serviceBusiness = new SortedList (); //獲取接口 public static IServices GetServiceBusiness(string endpointName) { IServices iServices; iServices = CreateWCFInterface(endpointName); if (_serviceBusiness.ContainsKey(endpointName)) { iServices = _serviceBusiness[endpointName]; } else { if (true) { iServices = CreateWCFInterface(endpointName); } _serviceBusiness.Add(endpointName, iServices); } return iServices; } //獲取WCF服務方法,使用代理工廠 private static IServices CreateWCFInterface(string endpointName) { return ServiceProxyFactory.Create (endpointName); } //獲取用戶服務 public static IUserSevice GetUserService(string endpointName) { return GetServiceBusiness(endpointName); } } }
3、建立代理工廠ServiceProxyFactory
namespace Modules.Factory.ServiceProxy { public static class ServiceProxyFactory { public static T Create(string endpointName) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(endpointName); } return (T)(new ServiceRealProxy (endpointName).GetTransparentProxy()); } } }
4、建立代理類RealProxy
namespace Modules.Factory.ServiceProxy { public class ServiceRealProxy5、建立通道工廠ChannelFactoryCreator: RealProxy { private readonly string _endpointName; public ServiceRealProxy(string endpointName): base(typeof(T)) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(endpointName); } this._endpointName = endpointName; } //重寫Invoke public override IMessage Invoke(IMessage msg) { T channel = ChannelFactoryCreator.Create (this._endpointName).CreateChannel(); IMethodCallMessage methodCall = (IMethodCallMessage)msg; IMethodReturnMessage methodReturn = null; object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[]; methodCall.Args.CopyTo(copiedArgs, 0); try { object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs); methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall); ((ICommunicationObject)channel).Close(); } catch (TargetInvocationException tiEx) { string title; if (tiEx.InnerException is NotSupportedException) { title =string.Concat( WCFExpetion, NotSupportedException, WCF服務契約異常); throw new Exception( string.Format({0}: {1}, title, tiEx.InnerException.Message), tiEx.InnerException); } else if (tiEx.InnerException is FaultException) { title = string.Concat(WCFExpetion, FaultException, 方法內部出現沒有處理的異常); throw new Exception(string.Format({0}: {1}, title, tiEx.InnerException.Message), tiEx.InnerException); } else if (tiEx.InnerException is CommunicationException) { title = string.Concat(WCFExpetion, CommunicationException, 網絡異常,請檢查地址是否正確); throw new Exception( string.Format({0}: {1}, title, tiEx.InnerException.Message), tiEx.InnerException); } else if (tiEx.InnerException is TimeoutException) { title = string.Concat(WCFExpetion, TimeoutException, 連接超時,請檢查網絡是否正常); throw new Exception( string.Format({0}: {1}, title, tiEx.InnerException.Message), tiEx.InnerException); } } catch (Exception ex) { throw new Exception(string.Format(WCF出現未知異常: {0}, ex.Message), ex); } finally { ((ICommunicationObject)channel).Abort(); } return methodReturn; } } }
namespace ICT.RCS.Modules.Factory.ServiceProxy { internal static class ChannelFactoryCreator { private static readonly Hashtable channelFactories = new Hashtable(); public static ChannelFactoryCreate (string endpointName) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException(endpointName); } ChannelFactory channelFactory = null; if (channelFactories.ContainsKey(endpointName)) { channelFactory = channelFactories[endpointName] as ChannelFactory ; } if (channelFactory == null) { channelFactory = new ChannelFactory (endpointName); lock (channelFactories.SyncRoot) { channelFactories[endpointName] = channelFactory; } } return channelFactory; } } }
6、引入工廠dll
要想使用WCF,我們以前是必須添加服務引用,而添加服務引用VS就會自動生成一個APP.CONFIG的配置文件,這個文件中配置了服務的地址以及訪問協議等內容。
現在,我們需要將上面的這些內容打包成dll並添加到引用。
7、配置app.config