|
|
///-----------------------------------------------------------------------
/// <copyright file="WsSoapExtention.cs" company="Origtek">
/// 程式代號: WsSoapExtention
/// 程式名稱: Web Service 處理狀態監控
/// 程式說明: Web Service 處理狀態監控
/// 起始作者: Allen
/// 起始日期: 2016/06/28
/// </copyright>
///-----------------------------------------------------------------------
#region 程式異動記錄
/// xx.YYYY/MM/DD VER AUTHOR COMMENTS(說明修改的內容)
/// 01.2016/06/28 1.0 Allen CREATE
#endregion
using log4net; using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Threading; using System.Web; using System.Web.Services.Protocols;
namespace CounsellorBL.Helper {
/// <summary>
/// 類別名稱: WsSoapExtention
/// 類別說明: Web Service 處理狀態監控
/// 起始作者: Allen
/// 起始日期: 2016/06/28
/// 最新修改人: Allen
/// 最新修日期: 2016/06/28
/// </summary>
public class WsSoapExtention : SoapExtension { #region 常數
/// <summary>
/// Web Service 最大執行時間,超過該時間,記錄Log
/// </summary>
private const int _iMaxRunningMilliseconds = 800; /// <summary>
/// 記錄最近執行的Web Service的筆數
/// </summary>
private const int LAST_INVOKE_CAPACITY = 20; /// <summary>
/// 用戶記錄最近執行的Web Service的筆數
/// </summary>
private const int USER_LAST_INVOKE_CAPACITY = 5; #endregion
#region 私有的成員變數(靜態的用於統計調用的信息;非靜態的用於記錄當前調用的WS的信息)
/// <summary>
/// 記錄當前調用的WS的信息
/// </summary>
private WSInvokeInfo _oInvokeInfo = new WSInvokeInfo();
/// <summary>
/// 寫Log
/// </summary>
private static readonly ILog _log = LogManager.GetLogger(typeof(WsSoapExtention)); /// <summary>
/// 用Timer定時記錄超時執行的Web Service
/// </summary>
private static System.Threading.Timer _tTimerSnap; /// <summary>
/// 執行中的Web Service
/// </summary>
private static ConcurrentDictionary<Guid, WSInvokeInfo> _diRunningWsMapping = new ConcurrentDictionary<Guid, WSInvokeInfo>(); /// <summary>
/// 記錄最近執行的20筆Web Service
/// </summary>
private static ConcurrentQueue<WSInvokeInfo> _quLastInvokeQueue = new ConcurrentQueue<WSInvokeInfo>(); /// <summary>
/// 按用戶IP統計用戶執行的Web Service
/// </summary>
private static ConcurrentDictionary<string, ConcurrentQueue<WSInvokeInfo>> _diRemoteUserHostInvokeMapping = new ConcurrentDictionary<string, ConcurrentQueue<WSInvokeInfo>>(); #endregion
#region 公開的成員變數
/// <summary>
/// 執行中的Web Service
/// </summary>
public static ConcurrentDictionary<Guid, WSInvokeInfo> RunningWsMapping { get { return _diRunningWsMapping; } } /// <summary>
/// 記錄最近執行的20筆Web Service
/// </summary>
public static ConcurrentQueue<WSInvokeInfo> LastInvokeQueue { get { return _quLastInvokeQueue; } } /// <summary>
/// 用戶IP列表
/// </summary>
public static RemoteHostInfo[] RemoteUserHosts { get { return _diRemoteUserHostInvokeMapping.ToList().ConvertAll(d => new RemoteHostInfo() { Host = d.Key, LastInvokes = d.Value.ToArray() }).ToArray(); } } #endregion
#region 靜態構造方法,用於初始化靜態成員變數(WsSoapExtention)
/// <summary>
/// 函式名稱:WsSoapExtention
/// 函式說明:靜態構造方法,用於初始化靜態成員變數
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
/// </summary>
static WsSoapExtention() { _tTimerSnap = new System.Threading.Timer(new TimerCallback(e => {
//if (RunningWsMapping.Count > 0)
//{
// var running = RunningWsMapping.ToList();
// running.ForEach(d =>
// {
// if (d.Value.UseTime.TotalMilliseconds > _iMaxRunningMilliseconds)
// {
// _log.WriteLog("WsSoapExtention : Web service invoke time is greater than max running time. InvokeInfo " + d.Value.ToString(), null, LoggingLevel.Warning);
// }
// });
//}
})); _tTimerSnap.Change(1000, 1000); } #endregion
#region SoapExtension需重寫的方法
public override System.IO.Stream ChainStream(System.IO.Stream stream) { return stream; }
public override object GetInitializer(Type serviceType) { return null; }
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; }
public override void Initialize(object initializer) { }
#region SoapExtension的重寫方法,用於記錄WS的執行信息(ProcessMessage)
/// <summary>
/// 函式名稱:ProcessMessage
/// 函式說明:SoapExtension的重寫方法,用於記錄WS的執行信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
/// </summary>
public override void ProcessMessage(SoapMessage message) { if (message is SoapClientMessage) { switch (message.Stage) { case SoapMessageStage.BeforeSerialize: break;
case SoapMessageStage.AfterSerialize: break;
case SoapMessageStage.BeforeDeserialize: break;
case SoapMessageStage.AfterDeserialize: break;
default: throw new Exception("No stage such as this."); } } else if (message is SoapServerMessage) { SoapServerMessage ssmMsg = (SoapServerMessage)message; WSInvokeInfo oRemovedInvokeInfo;
switch (message.Stage) { case SoapMessageStage.BeforeDeserialize: break;
case SoapMessageStage.AfterDeserialize: //開始執行時間
_oInvokeInfo.BeginInvokeTime = DateTime.Now; //執行的WS方法名
_oInvokeInfo.MethodName = message.MethodInfo.Name; //用戶IP
_oInvokeInfo.UserHostAddress = HttpContext.Current.Request.UserHostAddress; //參數
_oInvokeInfo.Args = message.MethodInfo.InParameters.ToDictionary(o => o.Name, o => message.GetInParameterValue(o.Position));
//將記錄加入執行中的WS映射中
_diRunningWsMapping.TryAdd(this._oInvokeInfo.Id, this._oInvokeInfo); //將記錄插入最近執行的隊列中
_quLastInvokeQueue.Enqueue(_oInvokeInfo); if (_quLastInvokeQueue.Count > LAST_INVOKE_CAPACITY) { //若隊列超過記錄上限,移除對頭
_quLastInvokeQueue.TryDequeue(out oRemovedInvokeInfo); } //將記錄插入用戶最近執行的隊列中
ConcurrentQueue<WSInvokeInfo> quUserLastInvokeQueue = _diRemoteUserHostInvokeMapping.GetOrAdd(_oInvokeInfo.UserHostAddress, new ConcurrentQueue<WSInvokeInfo>()); quUserLastInvokeQueue.Enqueue(_oInvokeInfo); if (quUserLastInvokeQueue.Count > USER_LAST_INVOKE_CAPACITY) { //若隊列超過記錄上限,移除對頭
quUserLastInvokeQueue.TryDequeue(out oRemovedInvokeInfo); } break;
case SoapMessageStage.BeforeSerialize: //結束執行時間
_oInvokeInfo.EndInvokeTime = DateTime.Now;
//將記錄從執行中的WS映射中移除
_diRunningWsMapping.TryRemove(_oInvokeInfo.Id, out oRemovedInvokeInfo);
//若當前WS的執行時間超過最大執行時間,寫Log
//if (_oInvokeInfo.UseTime.TotalMilliseconds > _iMaxRunningMilliseconds)
//{
// _log.WriteLog("WsSoapExtention : Web service invoke time is greater than max running time. InvokeInfo " + _oInvokeInfo.ToString(), null, LoggingLevel.Debug);
//}
break;
case SoapMessageStage.AfterSerialize: break;
default: throw new Exception("No stage such as this"); } } } #endregion
#endregion
}
#region Web Service 執行信息記錄(WSInvokeInfo)
/// <summary>
/// 類別名稱: WSInvokeInfo
/// 類別說明: Web Service 執行信息記錄
/// 起始作者: Allen
/// 起始日期: 2016/06/29
/// 最新修改人: Allen
/// 最新修日期: 2016/06/29
/// </summary>
public class WSInvokeInfo { /// <summary>
/// ID
/// </summary>
public Guid Id { get; private set; } /// <summary>
/// 開始執行時間
/// </summary>
public DateTime BeginInvokeTime { get; set; } /// <summary>
/// 結束執行時間
/// </summary>
public DateTime? EndInvokeTime { get; set; } /// <summary>
/// 使用時間
/// </summary>
public TimeSpan UseTime { get { return (EndInvokeTime.HasValue ? EndInvokeTime.Value : DateTime.Now) - BeginInvokeTime; } } /// <summary>
/// Ws方法名
/// </summary>
public string MethodName { get; set; } /// <summary>
/// 用戶IP
/// </summary>
public string UserHostAddress { get; set; } /// <summary>
/// 參數
/// </summary>
public Dictionary<string, object> Args { get; set; }
/// <summary>
/// 函式名稱:WSInvokeInfo
/// 函式說明:構造方法
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
/// </summary>
public WSInvokeInfo() { Id = Guid.NewGuid(); Args = new Dictionary<string, object>(); }
/// <summary>
/// 函式名稱:GetArgsDesc
/// 函式說明:獲取參數描述信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
/// </summary>
/// <returns>參數描述信息</returns>
public string GetArgsDesc() { List<string> lsArgsDesc = Args.ToList().ConvertAll(d => string.Format("{0}:={1}", d.Key, d.Value == null ? "null" : (d.Value is ICollection ? GetString((ICollection)d.Value) : d.Value.ToString()))); string sAllArgsDesck = string.Join(", ", lsArgsDesc); return sAllArgsDesck; }
/// <summary>
/// 顯示對象信息
/// </summary>
/// <returns></returns>
public override string ToString() { string sAllArgsDesck = GetArgsDesc(); return string.Format("Host: {0}, BeginInvokeTime: {1}, EndInvokeTime: {2}, UseTime: {3}, MethodName: {4}, Arg: {5}", UserHostAddress ?? "none", BeginInvokeTime, EndInvokeTime, UseTime.TotalMilliseconds, MethodName ?? "unkown", sAllArgsDesck); }
/// <summary>
/// 函式名稱:GetString
/// 函式說明:顯示集合的信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
/// </summary>
/// <param name="i_cCollection">集合</param>
/// <returns>集合的描述信息</returns>
private static string GetString(ICollection i_cCollection) { List<string> lsResult = new List<string>();
IEnumerator iterValues = i_cCollection.GetEnumerator(); while (iterValues.MoveNext()) { if (iterValues == null) { lsResult.Add("null"); } else if (iterValues.Current is ICollection) { lsResult.Add(GetString((ICollection)iterValues.Current)); } else { lsResult.Add(iterValues.Current.ToString()); } } return string.Concat("[", string.Join(", ", lsResult.ToArray()), "]"); } } #endregion
#region 調用WS的用戶信息(RemoteHostInfo)
/// <summary>
/// 類別名稱: RemoteHostInfo
/// 類別說明: 調用WS的用戶信息
/// 起始作者: Allen
/// 起始日期: 2016/06/29
/// 最新修改人: Allen
/// 最新修日期: 2016/06/29
/// </summary>
public class RemoteHostInfo { /// <summary>
/// IP
/// </summary>
public string Host { get; set; } /// <summary>
/// 記錄最後調用的WS
/// </summary>
public WSInvokeInfo[] LastInvokes { get; set; } } #endregion
}
|