我們在之前的博客已經完成過實例,大家也看到了如何使用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 ServiceRealProxy : 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;
}
}
}
5、建立通道工廠ChannelFactoryCreator
namespace ICT.RCS.Modules.Factory.ServiceProxy
{
internal static class ChannelFactoryCreator {
private static readonly Hashtable channelFactories = new Hashtable();
public static ChannelFactory Create(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