///-----------------------------------------------------------------------
///
/// 程式代號: WsSoapExtention
/// 程式名稱: Web Service 處理狀態監控
/// 程式說明: Web Service 處理狀態監控
/// 起始作者: Allen
/// 起始日期: 2016/06/28
///
///-----------------------------------------------------------------------
#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
{
///
/// 類別名稱: WsSoapExtention
/// 類別說明: Web Service 處理狀態監控
/// 起始作者: Allen
/// 起始日期: 2016/06/28
/// 最新修改人: Allen
/// 最新修日期: 2016/06/28
///
public class WsSoapExtention : SoapExtension
{
#region 常數
///
/// Web Service 最大執行時間,超過該時間,記錄Log
///
private const int _iMaxRunningMilliseconds = 800;
///
/// 記錄最近執行的Web Service的筆數
///
private const int LAST_INVOKE_CAPACITY = 20;
///
/// 用戶記錄最近執行的Web Service的筆數
///
private const int USER_LAST_INVOKE_CAPACITY = 5;
#endregion
#region 私有的成員變數(靜態的用於統計調用的信息;非靜態的用於記錄當前調用的WS的信息)
///
/// 記錄當前調用的WS的信息
///
private WSInvokeInfo _oInvokeInfo = new WSInvokeInfo();
///
/// 寫Log
///
private static readonly ILog _log = LogManager.GetLogger(typeof(WsSoapExtention));
///
/// 用Timer定時記錄超時執行的Web Service
///
private static System.Threading.Timer _tTimerSnap;
///
/// 執行中的Web Service
///
private static ConcurrentDictionary _diRunningWsMapping = new ConcurrentDictionary();
///
/// 記錄最近執行的20筆Web Service
///
private static ConcurrentQueue _quLastInvokeQueue = new ConcurrentQueue();
///
/// 按用戶IP統計用戶執行的Web Service
///
private static ConcurrentDictionary> _diRemoteUserHostInvokeMapping = new ConcurrentDictionary>();
#endregion
#region 公開的成員變數
///
/// 執行中的Web Service
///
public static ConcurrentDictionary RunningWsMapping { get { return _diRunningWsMapping; } }
///
/// 記錄最近執行的20筆Web Service
///
public static ConcurrentQueue LastInvokeQueue { get { return _quLastInvokeQueue; } }
///
/// 用戶IP列表
///
public static RemoteHostInfo[] RemoteUserHosts { get { return _diRemoteUserHostInvokeMapping.ToList().ConvertAll(d => new RemoteHostInfo() { Host = d.Key, LastInvokes = d.Value.ToArray() }).ToArray(); } }
#endregion
#region 靜態構造方法,用於初始化靜態成員變數(WsSoapExtention)
///
/// 函式名稱:WsSoapExtention
/// 函式說明:靜態構造方法,用於初始化靜態成員變數
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
///
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)
///
/// 函式名稱:ProcessMessage
/// 函式說明:SoapExtension的重寫方法,用於記錄WS的執行信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
///
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 quUserLastInvokeQueue = _diRemoteUserHostInvokeMapping.GetOrAdd(_oInvokeInfo.UserHostAddress, new ConcurrentQueue());
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)
///
/// 類別名稱: WSInvokeInfo
/// 類別說明: Web Service 執行信息記錄
/// 起始作者: Allen
/// 起始日期: 2016/06/29
/// 最新修改人: Allen
/// 最新修日期: 2016/06/29
///
public class WSInvokeInfo
{
///
/// ID
///
public Guid Id { get; private set; }
///
/// 開始執行時間
///
public DateTime BeginInvokeTime { get; set; }
///
/// 結束執行時間
///
public DateTime? EndInvokeTime { get; set; }
///
/// 使用時間
///
public TimeSpan UseTime { get { return (EndInvokeTime.HasValue ? EndInvokeTime.Value : DateTime.Now) - BeginInvokeTime; } }
///
/// Ws方法名
///
public string MethodName { get; set; }
///
/// 用戶IP
///
public string UserHostAddress { get; set; }
///
/// 參數
///
public Dictionary Args { get; set; }
///
/// 函式名稱:WSInvokeInfo
/// 函式說明:構造方法
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
///
public WSInvokeInfo()
{
Id = Guid.NewGuid();
Args = new Dictionary();
}
///
/// 函式名稱:GetArgsDesc
/// 函式說明:獲取參數描述信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
///
/// 參數描述信息
public string GetArgsDesc()
{
List 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;
}
///
/// 顯示對象信息
///
///
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);
}
///
/// 函式名稱:GetString
/// 函式說明:顯示集合的信息
/// 起始作者:Allen
/// 起始日期:2016/06/29
/// 最新修改人:Allen
/// 最新日期:2016/06/29
///
/// 集合
/// 集合的描述信息
private static string GetString(ICollection i_cCollection)
{
List lsResult = new List();
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)
///
/// 類別名稱: RemoteHostInfo
/// 類別說明: 調用WS的用戶信息
/// 起始作者: Allen
/// 起始日期: 2016/06/29
/// 最新修改人: Allen
/// 最新修日期: 2016/06/29
///
public class RemoteHostInfo
{
///
/// IP
///
public string Host { get; set; }
///
/// 記錄最後調用的WS
///
public WSInvokeInfo[] LastInvokes { get; set; }
}
#endregion
}