You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
371 lines
14 KiB
371 lines
14 KiB
///-----------------------------------------------------------------------
|
|
/// <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
|
|
}
|