Browse Source

Apewer-6.7.2

dev
王厅 2 years ago
parent
commit
0d041854fc
  1. 2
      Apewer.Source/Apewer.Source.csproj
  2. 3
      Apewer.Source/Source/Sqlite.cs
  3. 23
      Apewer.Web/Web/AspNetCoreServer.cs
  4. 2
      Apewer/Apewer.props
  5. 51
      Apewer/Json.cs
  6. 38
      Apewer/Network/HttpClient.cs
  7. 13
      Apewer/RuntimeUtility.cs
  8. 2
      Apewer/Web/ApiOptions.cs
  9. 67
      Apewer/Web/ApiProcessor.cs
  10. 4
      Apewer/Web/ApiResponse.cs
  11. 2
      Apewer/_Extensions.cs
  12. 10
      ChangeLog.md

2
Apewer.Source/Apewer.Source.csproj

@ -11,7 +11,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Apewer\Apewer.csproj" /> <ProjectReference Include="..\Apewer\Apewer.csproj" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.110" /> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.110" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">

3
Apewer.Source/Source/Sqlite.cs

@ -12,6 +12,7 @@ namespace Apewer.Source
{ {
/// <summary>连接 SQLite 数据库的客户端。</summary> /// <summary>连接 SQLite 数据库的客户端。</summary>
/// <remarks>Require System.Data.SQLite.Core v1.0.110</remarks>
public class Sqlite : DbClient public class Sqlite : DbClient
{ {
@ -61,7 +62,7 @@ namespace Apewer.Source
// 使用文件。 // 使用文件。
if (!File.Exists(path)) throw new FileNotFoundException("文件不存在。", path); if (!File.Exists(path)) throw new FileNotFoundException("文件不存在。", path);
_connstr = $"data source='{_path}'; version=3; "; _connstr = $"data source='{path}'; version=3; ";
_path = path; _path = path;
if (!string.IsNullOrEmpty(pass)) if (!string.IsNullOrEmpty(pass))
{ {

23
Apewer.Web/Web/AspNetCoreServer.cs

@ -14,6 +14,7 @@ using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication; using System.Security.Authentication;
using Microsoft.Extensions.Logging.Console;
namespace Apewer.Web namespace Apewer.Web
{ {
@ -38,6 +39,24 @@ namespace Apewer.Web
try try
{ {
_builder = Host.CreateDefaultBuilder(); _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) => _builder.ConfigureWebHostDefaults((builder) =>
{ {
Configure(builder); Configure(builder);
@ -117,6 +136,10 @@ namespace Apewer.Web
set { if (!_running) _compression = value; } set { if (!_running) _compression = value; }
} }
/// <summary>使用默认的控制台日志。</summary>
/// <remarks>默认值:TRUE</remarks>
public bool LogConsole { get; set; } = true;
#endregion #endregion
} }

2
Apewer/Apewer.props

@ -9,7 +9,7 @@
<Description></Description> <Description></Description>
<RootNamespace>Apewer</RootNamespace> <RootNamespace>Apewer</RootNamespace>
<Product>Apewer Libraries</Product> <Product>Apewer Libraries</Product>
<Version>6.7.1</Version> <Version>6.7.2</Version>
</PropertyGroup> </PropertyGroup>
<!-- 生成 --> <!-- 生成 -->

51
Apewer/Json.cs

@ -36,7 +36,7 @@ namespace Apewer
private static bool _recursively = true; private static bool _recursively = true;
[NonSerialized] [NonSerialized]
private static bool _forceall = false; private static bool _forceall = true;
/// <summary>允许产生 Exception,默认为不允许。</summary> /// <summary>允许产生 Exception,默认为不允许。</summary>
public static bool AllowException { get { return _throw; } set { _throw = value; } } public static bool AllowException { get { return _throw; } set { _throw = value; } }
@ -1166,17 +1166,20 @@ namespace Apewer
{ {
if (list == null) return null; if (list == null) return null;
if (list is IToJson) return ((IToJson)list).ToJson(); 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 checker = list as IToJsonChecker;
var json = NewArray(); var json = NewArray();
try 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) foreach (var item in list)
{ {
// 由 IToJsonChecker 实现的方法检查是否包含元素。 // 由 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 #endregion
#region Json -> String #region Json -> String
@ -1624,7 +1659,7 @@ namespace Apewer
} }
/// <summary>将 Json 填充到数组列表,失败时返回 NULL 值。</summary> /// <summary>将 Json 填充到数组列表,失败时返回 NULL 值。</summary>
internal static T[] Array<T>(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) where T : class, new() internal static T[] Array<T>(Json json, bool ignoreCase = true, string ignoreCharacters = null, bool force = false)
{ {
if (json == null) return null; if (json == null) return null;
if (json._jtoken == null) return null; if (json._jtoken == null) return null;

38
Apewer/Network/HttpClient.cs

@ -121,7 +121,9 @@ namespace Apewer.Network
} }
/// <summary>发送请求,并获取响应。</summary> /// <summary>发送请求,并获取响应。</summary>
public Exception Send() /// <param name="catchEx">捕获发生的异常,将异常作为返回值。</param>
/// <returns>发生的异常。</returns>
public Exception Send(bool catchEx = true)
{ {
lock (_locker) lock (_locker)
{ {
@ -134,7 +136,12 @@ namespace Apewer.Network
ResponseData = default; ResponseData = default;
var url = Url; 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; var method = Method;
if (method == HttpMethod.NULL) if (method == HttpMethod.NULL)
@ -143,21 +150,30 @@ namespace Apewer.Network
else method = HttpMethod.GET; 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); _request = Prepare(url, method);
_response = _request.GetResponse() as HttpWebResponse; _response = _request.GetResponse() as HttpWebResponse;
Parse(_response); Parse(_response);
return null;
}
catch (Exception ex)
{
_exception = ex;
if (ex is WebException webEx) Parse((HttpWebResponse)webEx.Response);
return ex;
} }
} }
return null;
} }
/// <exception cref="System.ArgumentException"></exception> /// <exception cref="System.ArgumentException"></exception>

13
Apewer/RuntimeUtility.cs

@ -794,16 +794,9 @@ namespace Apewer
if (action == null) return 0; if (action == null) return 0;
var stopwatch = new Stopwatch(); var stopwatch = new Stopwatch();
stopwatch.Start(); stopwatch.Start();
try action.Invoke();
{ stopwatch.Stop();
action.Invoke(); return stopwatch.ElapsedMilliseconds;
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
finally
{
stopwatch.Stop();
}
} }
#endregion #endregion

2
Apewer/Web/ApiOptions.cs

@ -7,7 +7,7 @@ namespace Apewer.Web
{ {
/// <summary>选项。</summary> /// <summary>选项。</summary>
public class ApiOptions public sealed class ApiOptions
{ {
/// <summary>允许压缩。</summary> /// <summary>允许压缩。</summary>

67
Apewer/Web/ApiProcessor.cs

@ -1,11 +1,7 @@
using Apewer.Network; using Apewer.Network;
using Apewer.Source; using Apewer.Source;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net; using System.Net;
using System.Reflection;
using static Apewer.Web.ApiUtility; using static Apewer.Web.ApiUtility;
@ -21,8 +17,7 @@ namespace Apewer.Web
internal Action<ApiCatch> Catcher = null; internal Action<ApiCatch> Catcher = null;
ApiOptions Options = null; ApiOptions Options = null;
Stopwatch Stopwatch = null; DateTime Begin = DateTime.UtcNow;
Uri Url = null; Uri Url = null;
HttpMethod Method = HttpMethod.NULL; HttpMethod Method = HttpMethod.NULL;
ApiRequest ApiRequest = null; ApiRequest ApiRequest = null;
@ -36,31 +31,21 @@ namespace Apewer.Web
public string Run() public string Run()
{ {
if (Options == null) Options = new ApiOptions(); if (Options == null) Options = new ApiOptions();
if (Options.WithDuration)
{
Stopwatch = new Stopwatch();
Stopwatch.Start();
}
var error = Flow(); var error = Flow();
if (Stopwatch != null)
{
Stopwatch.Stop();
Stopwatch = null;
}
return error; return error;
} }
string Flow() string Flow()
{ {
// 传入字段。
if (Provider == null) return "服务程序无效。";
if (Invoker == null) return "调用器无效。";
if (Entries == null) return "入口无效。";
Options = Invoker.Options ?? new ApiOptions();
Provider.Options = Options;
try try
{ {
// 传入字段。
if (Provider == null) return "服务程序无效。";
if (Invoker == null) return "调用器无效。";
if (Entries == null) return "入口无效。";
Options = Invoker.Options ?? new ApiOptions();
Provider.Options = Options;
// 检查执行的前提条件,获取 Method 和 URL。 // 检查执行的前提条件,获取 Method 和 URL。
var check = Check(); var check = Check();
if (!string.IsNullOrEmpty(check)) return check; if (!string.IsNullOrEmpty(check)) return check;
@ -77,28 +62,36 @@ namespace Apewer.Web
if (!string.IsNullOrEmpty(invoke)) return invoke; if (!string.IsNullOrEmpty(invoke)) return invoke;
// 输出。 // 输出。
if (Stopwatch != null) ApiResponse.Duration = Duration();
{
Stopwatch.Stop();
ApiResponse.Duration = Stopwatch.ElapsedMilliseconds;
Stopwatch = null;
}
Output(Provider, Options, ApiResponse, ApiRequest, Method); Output(Provider, Options, ApiResponse, ApiRequest, Method);
return null; return null;
} }
catch (Exception ex) catch (Exception ex)
{ {
if (Stopwatch != null)
{
Stopwatch.Stop();
Stopwatch = null;
}
var message = ex.Message(); var message = ex.Message();
Logger.Internals.Error(typeof(ApiInvoker), message); Logger.Internals.Error(typeof(ApiInvoker), message);
return 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() string Check()
{ {
// 服务程序检查。 // 服务程序检查。
@ -147,7 +140,7 @@ namespace Apewer.Web
Invoke(Entries.Get(appName)); Invoke(Entries.Get(appName));
if (Stopwatch != null) ApiResponse.Duration = Stopwatch.ElapsedMilliseconds; ApiResponse.Duration = Duration();
ApiResponse.Application = appName; ApiResponse.Application = appName;
ApiResponse.Function = funcName; ApiResponse.Function = funcName;
ApiResponse.Random = random; ApiResponse.Random = random;
@ -489,7 +482,7 @@ namespace Apewer.Web
// 包含 API 的处理时间。 // 包含 API 的处理时间。
if (options.WithDuration && response != null) if (options.WithDuration && response != null)
{ {
merged.Add("Duration", response.Duration.ToString() + "ms"); if (response.Duration.NotEmpty()) merged.Add("Duration", response.Duration);
} }
} }
if (response != null) if (response != null)
@ -534,7 +527,7 @@ namespace Apewer.Web
// 持续时间。 // 持续时间。
if (options.WithDuration) if (options.WithDuration)
{ {
json.SetProperty("duration", response.Duration); if (response.Duration.NotEmpty()) json.SetProperty("duration", response.Duration);
} }
// 随机值。 // 随机值。

4
Apewer/Web/ApiResponse.cs

@ -18,8 +18,8 @@ namespace Apewer.Web
internal bool StopReturn = false; internal bool StopReturn = false;
/// <summary>API 的执行时间,以毫秒为单位。</summary> /// <summary>API 的执行时间。</summary>
public long Duration { get; set; } public string Duration { get; set; }
/// <summary>Application。</summary> /// <summary>Application。</summary>
public string Application { get; set; } public string Application { get; set; }

2
Apewer/_Extensions.cs

@ -346,7 +346,7 @@ public static class Extensions
/// <param name="ignoreCase">忽略属性名称大小写。</param> /// <param name="ignoreCase">忽略属性名称大小写。</param>
/// <param name="ignoreChars">忽略的属性名称字符。</param> /// <param name="ignoreChars">忽略的属性名称字符。</param>
/// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param> /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
public static T[] Array<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) where T : class, new() => Apewer.Json.Array<T>(@this, ignoreCase, ignoreChars, force); public static T[] Array<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) => Apewer.Json.Array<T>(@this, ignoreCase, ignoreChars, force);
/// <summary>设置属性名称为小写。</summary> /// <summary>设置属性名称为小写。</summary>
public static Json Lower(this Json @this) => Apewer.Json.Lower(@this); public static Json Lower(this Json @this) => Apewer.Json.Lower(@this);

10
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 ### 6.7.1
- 问题修正 - 问题修正
- 修正了 Evaluate 可能不释放计时器的问题; - 修正了 Evaluate 可能不释放计时器的问题;

Loading…
Cancel
Save