剛學(xué)WCF的時(shí)候沒發(fā)現(xiàn)這個(gè)問題,調(diào)得很愉快卻沒有發(fā)現(xiàn)其實(shí)“暗藏殺機(jī)”,可謂危險(xiǎn)重重,還好后來覺得是有些不妥,于是google“WCF需要關(guān)閉嗎”,立馬找到了幾個(gè)博客園的鏈接,進(jìn)去一看,各位大俠均紛紛表示“關(guān)是一定要關(guān)的,但是你還不能用完就關(guān),因?yàn)殛P(guān)了,就不能再打開了,還得New,可以New的成本又有一點(diǎn)高”,好吧,這么說來就只有好好規(guī)劃一下了。
那么什么時(shí)候該關(guān)呢,答案是異常了的時(shí)候,MSDN給出了代碼(錯(cuò)誤處理部分,找不到鏈接了,見諒)
catch (CommunicationException)
{
client.Abort();
}
catch (TimeoutException)
{
clent.Abort();
}
所以這樣一來,就有了解決方案,那就是在每一處需要調(diào)用Wcf和代碼里加上try catch,大概就成了如下這樣
UserClient client = new UserClient();
try
{
client.Create(new User(){
UserName="xian",
Password="123"});
}
catch (CommunicationException)
{
client.Abort();
}
catch (TimeoutException)
{
clent.Abort();
}
這樣挺好的,沒錯(cuò),不過我們總不可能只調(diào)用一個(gè)Wcf接口吧,我們要調(diào)的可是一系列,也就是若干接口,那么就我們就需要寫很多重復(fù)的錯(cuò)誤處理代碼塊了。這樣原來沒什么問題,而且是理所當(dāng)然的事情?墒俏矣浀媚澄焕哮B說過當(dāng)代碼出現(xiàn)很大程度重復(fù)的時(shí)候你就該重構(gòu)它了(也是在博客園看到了,很普通但深入人心的道理),并且為了讓代碼好看一點(diǎn),我們還是想想好點(diǎn)的辦法。
如果你有些經(jīng)驗(yàn),肯定馬上就去想到使用委托來實(shí)現(xiàn)消除代碼的冗余,是的,下面就是我這次的實(shí)現(xiàn)方式,代碼如下:
ServiceInvokeHelper調(diào)用輔助類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Helper
{
/// <summary>
/// Wcf服務(wù)調(diào)用輔助類
/// </summary
public static class ServiceInvokeHelper<TChannel> where TChannel : ICommunicationObject, new()
{
#region private fields
private static Dictionary<string, TChannel> _ChannelDic = new Dictionary<string, TChannel>();
private static object _Lockhelper = new object();
private static TResult TryFunc<TResult>(Func<TChannel, TResult> func, TChannel channel)
{
string tChannelName = typeof(TChannel).FullName;
try
{
return func(channel);
}
catch (CommunicationException)
{
channel.Abort();
lock (_Lockhelper)
_ChannelDic.Remove(tChannelName);
throw;
}
catch (TimeoutException)
{
channel.Abort();
lock (_Lockhelper)
_ChannelDic.Remove(tChannelName);
throw;
}
catch (Exception)
{
channel.Abort();
lock (_Lockhelper)
_ChannelDic.Remove(tChannelName);
throw;
}
}
private static TChannel GetChannel()
{
TChannel instance;
string tChannelName = typeof(TChannel).FullName;
if (!_ChannelDic.ContainsKey(tChannelName))
{
lock (_Lockhelper)
{
instance = Activator.CreateInstance<TChannel>();
_ChannelDic.Add(tChannelName, instance);
}
}
else
{
instance = _ChannelDic[tChannelName];
}
if (instance.State != CommunicationState.Opened && instance.State != CommunicationState.Opening)
instance.Open();
return instance;
}
/// <summary>
/// 直接調(diào)用,無返回值
/// </summary>
public static void Invoke(Action<TChannel> action)
{
TChannel instance = GetChannel();
TryFunc(
client =>
{
action(client);
return (object)null;
}
, instance);
}
/// <summary>
/// 有返回值的調(diào)用
/// </summary>
public static TResult Invoke<TResult>(Func<TChannel, TResult> func)
{
TChannel instance = GetChannel();
ICommunicationObject channel = instance as ICommunicationObject;
TResult returnValue = default(TResult);
returnValue = TryFunc(func, instance);
return returnValue;
}
}
}
有了以上代碼,我們就可以這樣調(diào)Wcf了
ServiceInvokeHelper<UserClient>.Invoke(client=>client.Create({new User{
UserName="xian";
Password="123";
}}));
測試過程中發(fā)現(xiàn)這樣不支持out 和ref參數(shù)的調(diào)用,比如這樣是不可以的
public void GetUserList(int pageindex,int pagesize,ref count)
{
return ServiceInvokeHelper<UserClient>.Invoke(client=>client.GetUserList(pageindex,pagesize,ref count));
}
但是我們可以變通成如下模樣
public void GetUserList(int pageindex,int pagesize,ref count)
{
return ServiceInvokeHelper<UserClient>.Invoke(client=>
{
int tmpCount = -1;
client.GetUserList(pageindex,pagesize,ref tmpCount));
count = tmpCount;
}
}
是不是方便許多,并且也不但心因?yàn)殛P(guān)閉不及時(shí)造成連接數(shù)到達(dá)上限的情況,看起來不起眼的一個(gè)東西就分享到這時(shí),感謝你的閱讀!