3 Commits

  1. 49
      Apewer.Source/Source/ExecutingStatement.cs
  2. 59
      Apewer.Source/Source/SqlClient.cs
  3. 2
      Apewer/Apewer.props
  4. 16
      Apewer/Web/ApiInvoker.cs
  5. 28
      Apewer/Web/ApiMiddleware.cs
  6. 24
      Apewer/Web/ApiProcessor.cs
  7. 6
      ChangeLog.md

49
Apewer.Source/Source/ExecutingStatement.cs

@ -0,0 +1,49 @@
using System;
namespace Apewer.Source
{
/// <summary>正在执行的 SQL 语句。</summary>
[Serializable]
public sealed class ExecutingStatement
{
/// <summary></summary>
public long Session { get; set; }
/// <summary></summary>
public string Status { get; set; }
/// <summary></summary>
public long CpuTime { get; set; }
/// <summary></summary>
public long LogicalReads { get; set; }
/// <summary></summary>
public long Reads { get; set; }
/// <summary></summary>
public long Writes { get; set; }
/// <summary></summary>
public double ElapsedTime { get; set; }
/// <summary></summary>
public string StatementText { get; set; }
/// <summary></summary>
public string LoginName { get; set; }
/// <summary></summary>
public string HostName { get; set; }
/// <summary></summary>
public DateTime LoginTime { get; set; }
/// <summary></summary>
public long OpenTransactionCount { get; set; }
}
}

59
Apewer.Source/Source/SqlClient.cs

@ -782,6 +782,65 @@ COLLATE Chinese_PRC_CI_AS
return $"[{vcolumn.Field}] {type}"; return $"[{vcolumn.Field}] {type}";
} }
/// <summary>查询正在执行的语句,按执行时长降序排序。</summary>
/// <exception cref="ArgumentNullException" />
/// <exception cref="SqlException" />
public static ExecutingStatement[] QueryExecutingStatement(SqlClient source, int top = 100)
{
if (source == null) throw new ArgumentNullException(nameof(source));
var sql = top > 0 ? $"select top {top}" : "select";
sql = sql + @"
s.session_id,
r.status,
r.cpu_time,
r.logical_reads,
r.reads,
r.writes,
r.total_elapsed_time / 1000.0 as 'seconds',
r.command,
substring(
st.text,
(r.statement_start_offset / 2) + 1,
((case r.statement_end_offset when -1 then datalength(st.text) else r.statement_end_offset end - r.statement_start_offset) / 2) + 1
) as statement_text,
s.login_name,
s.host_name,
s.login_time,
r.open_transaction_count
from sys.dm_exec_sessions as s
join sys.dm_exec_requests as r on r.session_id = s.session_id cross apply sys.dm_exec_sql_text(r.sql_handle) as st
where r.session_id != @@spid
order by r.cpu_time desc
";
using (var query = source.Query(sql))
{
if (!query.Success) throw new SqlException(query);
var rows = query.Rows;
var records = new List<ExecutingStatement>(rows);
for (var i = 0; i < rows; i++)
{
var record = new ExecutingStatement();
record.Session = query.Int64(i, "session_id");
record.Status = query.Text(i, "status");
record.CpuTime = query.Int64(i, "cpu_time");
record.LogicalReads = query.Int64(i, "logical_reads");
record.Reads = query.Int64(i, "reads");
record.Writes = query.Int64(i, "writes");
record.ElapsedTime = query.Double(i, "seconds");
record.StatementText = query.Text(i, "statement_text");
record.LoginName = query.Text(i, "login_name");
record.HostName = query.Text(i, "host_name");
record.LoginTime = query.DateTime(i, "login_time").Value;
record.OpenTransactionCount = query.Int64(i, "open_transaction_count");
records.Add(record);
}
return records.ToArray();
}
}
#endregion #endregion
} }

2
Apewer/Apewer.props

@ -7,7 +7,7 @@
<Description></Description> <Description></Description>
<RootNamespace>Apewer</RootNamespace> <RootNamespace>Apewer</RootNamespace>
<Product>Apewer Libraries</Product> <Product>Apewer Libraries</Product>
<Version>6.8.6</Version>
<Version>6.8.7</Version>
</PropertyGroup> </PropertyGroup>
<!-- 生成 --> <!-- 生成 -->

16
Apewer/Web/ApiInvoker.cs

@ -41,16 +41,24 @@ namespace Apewer.Web
#region 中间件 #region 中间件
private List<Type> _middlewares = new List<Type>();
private List<ApiMiddleware> _middlewares = new List<ApiMiddleware>();
/// <summary>中间件。</summary> /// <summary>中间件。</summary>
public Type[] Middlewares { get => _middlewares.ToArray(); }
internal ApiMiddleware[] Middlewares { get => _middlewares.ToArray(); }
/// <summary>添加中间件。</summary> /// <summary>添加中间件。</summary>
public void AddMiddleware<T>() where T : class, IApiMiddleware, new() public void AddMiddleware<T>() where T : class, IApiMiddleware, new()
{ {
var type = typeof(T);
_middlewares.Add(type);
var middleware = new ApiMiddleware(typeof(T));
_middlewares.Add(middleware);
}
/// <summary>添加中间件。</summary>
/// <exception cref="ArgumentNullException" />
public void AddMiddleware(Action<ApiContext, Action> callback)
{
if (callback == null) throw new ArgumentNullException(nameof(callback));
_middlewares.Add(new ApiMiddleware(callback));
} }
#endregion #endregion

28
Apewer/Web/ApiMiddleware.cs

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Apewer.Web
{
internal class ApiMiddleware
{
internal Type Type;
internal Action<ApiContext, Action> Callback;
public ApiMiddleware(Type type)
{
if (!typeof(IApiMiddleware).IsAssignableFrom(type)) throw new NotImplementedException($"类型【{type.FullName}】未实现【{nameof(IApiMiddleware)}】。");
Type = type;
}
public ApiMiddleware(Action<ApiContext, Action> callback)
{
if (callback == null) throw new ArgumentNullException(nameof(callback));
Callback = callback;
}
}
}

24
Apewer/Web/ApiProcessor.cs

@ -60,7 +60,7 @@ namespace Apewer.Web
if (middlewares.Length > 0) if (middlewares.Length > 0)
{ {
// 设置队列和回调。 // 设置队列和回调。
_mw_queue = new Queue<Type>(middlewares);
_mw_queue = new Queue<ApiMiddleware>(middlewares);
_context.SetMiddlewareCallback(MiddlewareNext); _context.SetMiddlewareCallback(MiddlewareNext);
// 执行。 // 执行。
@ -263,7 +263,7 @@ namespace Apewer.Web
#region middleware #region middleware
Queue<Type> _mw_queue = null;
Queue<ApiMiddleware> _mw_queue = null;
void MiddlewareNext(ApiContext context) void MiddlewareNext(ApiContext context)
{ {
@ -274,13 +274,23 @@ namespace Apewer.Web
} }
// 创建下一个中间件的实例 // 创建下一个中间件的实例
var type = _mw_queue.Dequeue();
var instance = Activator.CreateInstance(type);
var middleware = instance as IApiMiddleware;
if (middleware == null) throw new Exception($"类型【{type.FullName}】不是有效的中间件。");
var middleware = _mw_queue.Dequeue();
if (middleware.Type != null)
{
var instance = Activator.CreateInstance(middleware.Type) as IApiMiddleware;
if (instance == null) throw new Exception($"类型【{middleware.Type.FullName}】不是有效的中间件。");
// 调用 // 调用
middleware.Invoke(context);
instance.Invoke(context);
}
else if (middleware.Callback != null)
{
middleware.Callback.Invoke(context, () => MiddlewareNext(context));
}
else
{
MiddlewareNext(context);
}
} }
// 执行路由。 // 执行路由。

6
ChangeLog.md

@ -1,4 +1,8 @@

### 6.8.7
- 增加 TextUtility.Distinct 方法,对字符串集合去重;
- 增加 ApiInvoker.AddMiddleware 方法,以支持中间件;
- 增加 SqlClient.QueryExecutingStatement 方法,用于查询正在执行的语句。
### 6.8.6 ### 6.8.6
- 新特性 - 新特性
- Logger.Default 默认启用日志文件,保留 30 天; - Logger.Default 默认启用日志文件,保留 30 天;

Loading…
Cancel
Save