在我們的系統里有多個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要復制到程序的跟目錄下或者指定的文件下。