在我們的系統裡有多個wcf支撐。但是有的時候會莫名的停止,于是今天寫了一個服務,定時去檢測其他wcf服務是否線上。那麼最簡單的辦法自然是引用其他wcf服務讓vs給我們自動生成clientProxy然後一個個去調用是否正常。但是這種辦法顯然不是我要的。我要弄一個通用的服務檢測。
方案1:
對于httpbinding的wcf服務有個最簡單的檢測方法:就是用httpClient去請求一下服務位址看有沒有服務描述xml傳回。如果有就是live不然就是服務異常關閉了。這個方法對于net.tcp綁定等不适用。
方案2:
使用反射動态生成channelProxy然後去嘗試執行一個方法。當然這個方法最好不是Update等會影響到業務資料的方法,最好是query級别的方法。
正常使用ChannelFactory<T>調用wcf服務:
var channelFactory = new ChannelFactory<T>(endpoint);
var proxy = this._channelFactory.CreateChannel();
proxy.Add(1,2);
很簡單,我們隻需要把T接口協定,endpoint節點名稱,調用的方法名稱,以及程式集名稱或者路徑提取到配置檔案裡就行了。然後把上面的代碼轉換成反射代碼就行。
看一下最主要的方法吧,廢話不多了。
private bool IsLive(string assemblyName, string apiServiceFullName, string endpointName, string testMethodName)
{
var basePath = AppDomain.CurrentDomain.BaseDirectory;
Type apiType = null;
var asm = Assembly.LoadFrom(basePath + "/services/" + assemblyPath);
apiType = asm.GetType(apiServiceFullName);
var channelType = typeof(ChannelFactory<>).MakeGenericType(apiType);
try
{
FuncExtension.TryDo(() =>
{
var channel = Activator.CreateInstance(channelType, endpointName);
Type[] types = new Type[0];
var createChannelMethod = channelType.GetMethod("CreateChannel", types);
var proxy = createChannelMethod.Invoke(channel, null);
try
{
var testMethod = apiType.GetMethod(testMethodName);
var patameterInfos = testMethod.GetParameters();
List<object> parameters = new List<object>();
foreach (var patameterInfo in patameterInfos)
{
var defaultValue = patameterInfo.ParameterType.IsValueType
? Activator.CreateInstance(patameterInfo.ParameterType)
: null;
parameters.Add(defaultValue);
}
testMethod.Invoke(proxy, parameters.ToArray());
}
catch (Exception exc)
{
Logger.Error(
string.Format("Try to connect wcf service error:{0}, ExceptionType:{1}", endpointName,
exc.GetType()), GetType(), exc);
throw;
}
finally
{
try
{
(proxy as ICommunicationObject).Close();
}
catch
{
(proxy as ICommunicationObject).Abort();
}
}
}, 3);
return true;
}
catch (Exception exc)
{
PrintWholeException(exc);
return !IsHttpOrSocketException(exc);
}
}
private void PrintWholeException(Exception exc)
{
Logger.Error(exc.GetType().ToString(), GetType(), exc);
if (exc.InnerException != null)
{
PrintWholeException(exc.InnerException);
}
}
private bool IsHttpOrSocketException(Exception exc)
{
if (exc is EndpointNotFoundException || exc is SocketException)
{
return true;
}
else
{
if (exc.InnerException != null)
{
return IsHttpOrSocketException(exc.InnerException);
}
}
return false;
}
其中FuncExtension.TryDo是自動嘗試一個Actoin的封裝,不影響了解反射的代碼。
我們的目的是判斷wcf是否還live,是以不要在意傳回值。我們隻要判斷這次調用的異常是否是SocketException或者EndpointNotFindException即可。
這樣,當需要監控新的wcf服務的時候隻要在配置檔案裡添加一行協定,程式集,調用方法,endpoint的配置即可,當然協定所在的dll要複制到程式的跟目錄下或者指定的檔案下。
QQ群:1022985150 一起探讨學習.NET技術
作者:Agile.Zhou(kklldog)