diff --git a/Apewer.Source/Apewer.Source.csproj b/Apewer.Source/Apewer.Source.csproj
index ae9a2a0..c0664e0 100644
--- a/Apewer.Source/Apewer.Source.csproj
+++ b/Apewer.Source/Apewer.Source.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/Apewer.Source/Source/Sqlite.cs b/Apewer.Source/Source/Sqlite.cs
index b794284..5405562 100644
--- a/Apewer.Source/Source/Sqlite.cs
+++ b/Apewer.Source/Source/Sqlite.cs
@@ -12,6 +12,7 @@ namespace Apewer.Source
{
/// 连接 SQLite 数据库的客户端。
+ /// Require System.Data.SQLite.Core v1.0.110
public class Sqlite : DbClient
{
@@ -61,7 +62,7 @@ namespace Apewer.Source
// 使用文件。
if (!File.Exists(path)) throw new FileNotFoundException("文件不存在。", path);
- _connstr = $"data source='{_path}'; version=3; ";
+ _connstr = $"data source='{path}'; version=3; ";
_path = path;
if (!string.IsNullOrEmpty(pass))
{
diff --git a/Apewer.Web/Web/AspNetCoreServer.cs b/Apewer.Web/Web/AspNetCoreServer.cs
index 289aeed..1222f53 100644
--- a/Apewer.Web/Web/AspNetCoreServer.cs
+++ b/Apewer.Web/Web/AspNetCoreServer.cs
@@ -14,6 +14,7 @@ using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Authentication;
+using Microsoft.Extensions.Logging.Console;
namespace Apewer.Web
{
@@ -38,6 +39,24 @@ namespace Apewer.Web
try
{
_builder = Host.CreateDefaultBuilder();
+
+ if (!LogConsole)
+ {
+ _builder.ConfigureLogging((context, builder) =>
+ {
+ if (context.HostingEnvironment.IsProduction())
+ {
+ foreach (var sd in builder.Services)
+ {
+ if (sd.ImplementationType.Equals(typeof(ConsoleLoggerProvider)))
+ {
+ builder.Services.Remove(sd);
+ break;
+ }
+ }
+ }
+ });
+ }
_builder.ConfigureWebHostDefaults((builder) =>
{
Configure(builder);
@@ -117,6 +136,10 @@ namespace Apewer.Web
set { if (!_running) _compression = value; }
}
+ /// 使用默认的控制台日志。
+ /// 默认值:TRUE
+ public bool LogConsole { get; set; } = true;
+
#endregion
}
diff --git a/Apewer/Apewer.props b/Apewer/Apewer.props
index 5099d3b..1d64731 100644
--- a/Apewer/Apewer.props
+++ b/Apewer/Apewer.props
@@ -9,7 +9,7 @@
Apewer
Apewer Libraries
- 6.7.1
+ 6.7.2
diff --git a/Apewer/Json.cs b/Apewer/Json.cs
index 2ba0525..a59f9b7 100644
--- a/Apewer/Json.cs
+++ b/Apewer/Json.cs
@@ -36,7 +36,7 @@ namespace Apewer
private static bool _recursively = true;
[NonSerialized]
- private static bool _forceall = false;
+ private static bool _forceall = true;
/// 允许产生 Exception,默认为不允许。
public static bool AllowException { get { return _throw; } set { _throw = value; } }
@@ -1166,17 +1166,20 @@ namespace Apewer
{
if (list == null) return null;
if (list is IToJson) return ((IToJson)list).ToJson();
- // IList 不再需要 SerializableAttribute 特性。
- // {
- // var ltype = list.GetType();
- // var sas = ltype.GetCustomAttributes(typeof(SerializableAttribute), false);
- // if (sas == null || sas.Length < 1) return null;
- // }
var checker = list as IToJsonChecker;
var json = NewArray();
try
{
+ if (list is Array array)
+ {
+ if (array != null && array.Rank > 1)
+ {
+ ToJson(json, array, array.Rank, new int[0]);
+ return json;
+ }
+ }
+
foreach (var item in list)
{
// 由 IToJsonChecker 实现的方法检查是否包含元素。
@@ -1584,6 +1587,38 @@ namespace Apewer
}
}
+ private static void ToJson(Json parent, Array array, int rank, int[] indices)
+ {
+ var dimension = indices.Length;
+
+ var subIndices = new int[dimension + 1];
+ if (dimension > 0) indices.CopyTo(subIndices, 0);
+ var subLength = array.GetLength(dimension);
+
+ var end = dimension + 1 >= rank;
+ if (end)
+ {
+ var subLinear = new object[subLength];
+ for (var i = 0; i < subLength; i++)
+ {
+ subIndices[dimension] = i;
+ subLinear[i] = array.GetValue(subIndices);
+ }
+ var subJson = Json.From(subLinear);
+ parent.Reset(subJson);
+ }
+ else
+ {
+ for (var i = 0; i < subLength; i++)
+ {
+ subIndices[dimension] = i;
+ var subJson = Json.NewArray();
+ ToJson(subJson, array, rank, subIndices);
+ parent.AddItem(subJson);
+ }
+ }
+ }
+
#endregion
#region Json -> String
@@ -1624,7 +1659,7 @@ namespace Apewer
}
/// 将 Json 填充到数组列表,失败时返回 NULL 值。
- internal static T[] Array(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) where T : class, new()
+ internal static T[] Array(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false)
{
if (json == null) return null;
if (json._jtoken == null) return null;
diff --git a/Apewer/Network/HttpClient.cs b/Apewer/Network/HttpClient.cs
index 4167497..e313ac3 100644
--- a/Apewer/Network/HttpClient.cs
+++ b/Apewer/Network/HttpClient.cs
@@ -121,7 +121,9 @@ namespace Apewer.Network
}
/// 发送请求,并获取响应。
- public Exception Send()
+ /// 捕获发生的异常,将异常作为返回值。
+ /// 发生的异常。
+ public Exception Send(bool catchEx = true)
{
lock (_locker)
{
@@ -134,7 +136,12 @@ namespace Apewer.Network
ResponseData = default;
var url = Url;
- if (url.IsEmpty()) return Return(new MissingMemberException("未指定 URL。"));
+ if (url.IsEmpty())
+ {
+ var ex = new MissingMemberException("未指定 URL。");
+ if (!catchEx) throw ex;
+ return Return(ex);
+ }
var method = Method;
if (method == HttpMethod.NULL)
@@ -143,21 +150,30 @@ namespace Apewer.Network
else method = HttpMethod.GET;
}
- try
+ if (catchEx)
+ {
+ try
+ {
+ _request = Prepare(url, method);
+ _response = _request.GetResponse() as HttpWebResponse;
+ Parse(_response);
+ }
+ catch (Exception ex)
+ {
+ _exception = ex;
+ if (ex is WebException webEx) Parse((HttpWebResponse)webEx.Response);
+ return ex;
+ }
+ }
+ else
{
_request = Prepare(url, method);
_response = _request.GetResponse() as HttpWebResponse;
Parse(_response);
- return null;
- }
- catch (Exception ex)
- {
- _exception = ex;
- if (ex is WebException webEx) Parse((HttpWebResponse)webEx.Response);
- return ex;
}
-
}
+
+ return null;
}
///
diff --git a/Apewer/RuntimeUtility.cs b/Apewer/RuntimeUtility.cs
index 282f495..88a1175 100644
--- a/Apewer/RuntimeUtility.cs
+++ b/Apewer/RuntimeUtility.cs
@@ -794,16 +794,9 @@ namespace Apewer
if (action == null) return 0;
var stopwatch = new Stopwatch();
stopwatch.Start();
- try
- {
- action.Invoke();
- stopwatch.Stop();
- return stopwatch.ElapsedMilliseconds;
- }
- finally
- {
- stopwatch.Stop();
- }
+ action.Invoke();
+ stopwatch.Stop();
+ return stopwatch.ElapsedMilliseconds;
}
#endregion
diff --git a/Apewer/Web/ApiOptions.cs b/Apewer/Web/ApiOptions.cs
index 2398f02..9911dc8 100644
--- a/Apewer/Web/ApiOptions.cs
+++ b/Apewer/Web/ApiOptions.cs
@@ -7,7 +7,7 @@ namespace Apewer.Web
{
/// 选项。
- public class ApiOptions
+ public sealed class ApiOptions
{
/// 允许压缩。
diff --git a/Apewer/Web/ApiProcessor.cs b/Apewer/Web/ApiProcessor.cs
index fcb9991..a916057 100644
--- a/Apewer/Web/ApiProcessor.cs
+++ b/Apewer/Web/ApiProcessor.cs
@@ -1,11 +1,7 @@
using Apewer.Network;
using Apewer.Source;
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
using System.Net;
-using System.Reflection;
using static Apewer.Web.ApiUtility;
@@ -21,8 +17,7 @@ namespace Apewer.Web
internal Action Catcher = null;
ApiOptions Options = null;
- Stopwatch Stopwatch = null;
-
+ DateTime Begin = DateTime.UtcNow;
Uri Url = null;
HttpMethod Method = HttpMethod.NULL;
ApiRequest ApiRequest = null;
@@ -36,31 +31,21 @@ namespace Apewer.Web
public string Run()
{
if (Options == null) Options = new ApiOptions();
- if (Options.WithDuration)
- {
- Stopwatch = new Stopwatch();
- Stopwatch.Start();
- }
var error = Flow();
- if (Stopwatch != null)
- {
- Stopwatch.Stop();
- Stopwatch = null;
- }
return error;
}
string Flow()
{
+ // 传入字段。
+ if (Provider == null) return "服务程序无效。";
+ if (Invoker == null) return "调用器无效。";
+ if (Entries == null) return "入口无效。";
+ Options = Invoker.Options ?? new ApiOptions();
+ Provider.Options = Options;
+
try
{
- // 传入字段。
- if (Provider == null) return "服务程序无效。";
- if (Invoker == null) return "调用器无效。";
- if (Entries == null) return "入口无效。";
- Options = Invoker.Options ?? new ApiOptions();
- Provider.Options = Options;
-
// 检查执行的前提条件,获取 Method 和 URL。
var check = Check();
if (!string.IsNullOrEmpty(check)) return check;
@@ -77,28 +62,36 @@ namespace Apewer.Web
if (!string.IsNullOrEmpty(invoke)) return invoke;
// 输出。
- if (Stopwatch != null)
- {
- Stopwatch.Stop();
- ApiResponse.Duration = Stopwatch.ElapsedMilliseconds;
- Stopwatch = null;
- }
+ ApiResponse.Duration = Duration();
Output(Provider, Options, ApiResponse, ApiRequest, Method);
return null;
}
catch (Exception ex)
{
- if (Stopwatch != null)
- {
- Stopwatch.Stop();
- Stopwatch = null;
- }
var message = ex.Message();
Logger.Internals.Error(typeof(ApiInvoker), message);
return message;
}
}
+ string Duration()
+ {
+ var span = DateTime.UtcNow - Begin;
+ var ms = span.TotalMilliseconds;
+ if (ms > 0D)
+ {
+ var s = span.TotalMilliseconds / 1000D;
+ if (s > 10D) return Math.Round(s, 1).ToString() + "s";
+ if (s > 1D) return Math.Round(s, 2).ToString() + "s";
+ if (ms > 10D) return Math.Round(ms, 0).ToString() + "ms";
+ return Math.Round(ms, 1).ToString() + "ms";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
string Check()
{
// 服务程序检查。
@@ -147,7 +140,7 @@ namespace Apewer.Web
Invoke(Entries.Get(appName));
- if (Stopwatch != null) ApiResponse.Duration = Stopwatch.ElapsedMilliseconds;
+ ApiResponse.Duration = Duration();
ApiResponse.Application = appName;
ApiResponse.Function = funcName;
ApiResponse.Random = random;
@@ -489,7 +482,7 @@ namespace Apewer.Web
// 包含 API 的处理时间。
if (options.WithDuration && response != null)
{
- merged.Add("Duration", response.Duration.ToString() + "ms");
+ if (response.Duration.NotEmpty()) merged.Add("Duration", response.Duration);
}
}
if (response != null)
@@ -534,7 +527,7 @@ namespace Apewer.Web
// 持续时间。
if (options.WithDuration)
{
- json.SetProperty("duration", response.Duration);
+ if (response.Duration.NotEmpty()) json.SetProperty("duration", response.Duration);
}
// 随机值。
diff --git a/Apewer/Web/ApiResponse.cs b/Apewer/Web/ApiResponse.cs
index 9472be5..ac84c94 100644
--- a/Apewer/Web/ApiResponse.cs
+++ b/Apewer/Web/ApiResponse.cs
@@ -18,8 +18,8 @@ namespace Apewer.Web
internal bool StopReturn = false;
- /// API 的执行时间,以毫秒为单位。
- public long Duration { get; set; }
+ /// API 的执行时间。
+ public string Duration { get; set; }
/// Application。
public string Application { get; set; }
diff --git a/Apewer/_Extensions.cs b/Apewer/_Extensions.cs
index 2f006d7..58ab8d9 100644
--- a/Apewer/_Extensions.cs
+++ b/Apewer/_Extensions.cs
@@ -346,7 +346,7 @@ public static class Extensions
/// 忽略属性名称大小写。
/// 忽略的属性名称字符。
/// 强制填充,忽略 的 Serializable 特性。
- public static T[] Array(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) where T : class, new() => Apewer.Json.Array(@this, ignoreCase, ignoreChars, force);
+ public static T[] Array(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) => Apewer.Json.Array(@this, ignoreCase, ignoreChars, force);
/// 设置属性名称为小写。
public static Json Lower(this Json @this) => Apewer.Json.Lower(@this);
diff --git a/ChangeLog.md b/ChangeLog.md
index 3392e22..452fe58 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,16 @@
### 最新提交
+### 6.7.2
+- 问题修正
+ - 修正了 SQLite 的构造函数中的 path 参数;
+ - Apewer.Source 不再包含对 System.Data.SQLite.Core 的依赖,最终代码项目中需要额外添加引用。
+- 新特性
+ - Json 强制序列化选项已修改为 true,以简化最终代码;
+ - Json 解析新增支持数组类型,提升性能;
+ - HttpClient 增加了参数 catchEx = true;
+ - AspNetCoreServer 新增了 LogConsole 属性,默认值为 true,用于配置控制台输出。
+
### 6.7.1
- 问题修正
- 修正了 Evaluate 可能不释放计时器的问题;