Elivo 1 month ago
parent
commit
452659df1c
  1. 108
      Apewer.Windows/Apewer.Windows.csproj
  2. 44
      Apewer.Windows/WindowsUtility.cs
  3. 98
      Apewer/Apewer.csproj
  4. 35
      Apewer/BytesUtility.cs
  5. 83
      Apewer/CollectionUtility.cs
  6. 123
      Apewer/DrawingUtility.cs
  7. 2
      Apewer/Logger.cs
  8. 1
      Apewer/NumberUtility.cs
  9. 2
      Apewer/Source/Execute.cs
  10. 2
      Apewer/Source/Query.cs
  11. 351
      Apewer/Source/SourceUtility.cs
  12. 21
      Apewer/Source/SqlException.cs
  13. 2
      Apewer/StorageUtility.cs
  14. 5
      Apewer/TextUtility.cs
  15. 3
      Apewer/Web/IApiMiddleware.cs
  16. 2
      Apewer/_Extensions.cs

108
Apewer.Windows/Apewer.Windows.csproj

@ -1,64 +1,66 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Apewer\Apewer.props" />
<Import Project="..\Apewer\Apewer.props" />
<PropertyGroup>
<NoWarn>CS0108;CS0612</NoWarn>
<TargetFrameworks>net461;net40;net20;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<PropertyGroup>
<NoWarn>CS0108;CS0612</NoWarn>
<TargetFrameworks>net461;net40;net20;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<!-- 打包 -->
<PropertyGroup>
<Description>实现 Windows 程序功能。</Description>
</PropertyGroup>
<!-- 打包 -->
<PropertyGroup>
<Description>实现 Windows 程序功能。</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Apewer\Apewer.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Apewer\Apewer.csproj" />
</ItemGroup>
<!-- .NET Core 3.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<!-- <UseWPF>true</UseWPF> -->
<!-- <UseWindowsForms>true</UseWindowsForms> -->
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<!-- <FrameworkReference Include="Microsoft.AspNetCore.App" /> -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />
<!--<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />-->
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" />
</ItemGroup>
<!-- .NET Core 3.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<!-- <UseWPF>true</UseWPF> -->
<!-- <UseWindowsForms>true</UseWindowsForms> -->
<DefineConstants>DRAWING;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<!-- <FrameworkReference Include="Microsoft.AspNetCore.App" /> -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />
<!--<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />-->
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" />
<Compile Include="..\Apewer\DrawingUtility.cs" />
</ItemGroup>
<!-- .NET Framework 4.6.1 -->
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="CustomMarshalers" />
<Reference Include="PresentationCore" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Speech" />
<Reference Include="System.Windows.Forms" />
<Reference Include="WindowsBase" />
</ItemGroup>
<!-- .NET Framework 4.6.1 -->
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="CustomMarshalers" />
<Reference Include="PresentationCore" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Speech" />
<Reference Include="System.Windows.Forms" />
<Reference Include="WindowsBase" />
</ItemGroup>
<!-- .NET Framework 4.0 -->
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="CustomMarshalers" />
<Reference Include="PresentationCore" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Speech" />
<Reference Include="System.Windows.Forms" />
<Reference Include="WindowsBase" />
</ItemGroup>
<!-- .NET Framework 4.0 -->
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="CustomMarshalers" />
<Reference Include="PresentationCore" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Speech" />
<Reference Include="System.Windows.Forms" />
<Reference Include="WindowsBase" />
</ItemGroup>
<!-- .NET Framework 2.0 -->
<ItemGroup Condition="'$(TargetFramework)'=='net20'">
<Reference Include="CustomMarshalers" />
<Reference Include="System.Configuration" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Framework 2.0 -->
<ItemGroup Condition="'$(TargetFramework)'=='net20'">
<Reference Include="CustomMarshalers" />
<Reference Include="System.Configuration" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess " />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
</Project>

44
Apewer.Windows/WindowsUtility.cs

@ -1039,26 +1039,30 @@ namespace Apewer
#if NETFX
/// <summary>创建快捷方式。</summary>
/// <param name="linkPath">快捷方式路径。</param>
/// <summary>创建快捷方式,生成 .lnk 文件。</summary>
/// <param name="linkPath">快捷方式路径,以 .lnk 结尾。</param>
/// <param name="linkIcon">快捷方式图标。可使用 c:\source.exe,0 格式。</param>
/// <param name="linkDescription">快捷方式说明。</param>
/// <param name="sourcePath">源路径。</param>
/// <param name="sourceArgs">源参数。</param>
/// <param name="directory">工作目录。</param>
/// <exception cref="ArgumentNullException" />
public static void CreateShortcut(string linkPath, string sourcePath, string sourceArgs = null, string linkIcon = null, string linkDescription = null, string directory = null)
{
// var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// var shortcut = (IWshShortcut)new WshShellClass().CreateShortcut(linkPath);
if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath));
if (sourcePath.IsEmpty()) throw new ArgumentNullException(nameof(sourcePath));
var wshShellClass = new IWshRuntimeLibrary.WshShellClass();
var wshObject = wshShellClass.CreateShortcut(linkPath);
var wshShortcut = (IWshRuntimeLibrary.IWshShortcut)wshObject;
var shortcut = wshShortcut;
shortcut.TargetPath = sourcePath ?? "";
shortcut.Arguments = sourceArgs ?? "arg1";
shortcut.Description = linkDescription ?? "Invalid Description";
shortcut.Arguments = sourceArgs ?? "";
shortcut.Description = linkDescription ?? "";
shortcut.WorkingDirectory = directory ?? "";
shortcut.IconLocation = linkIcon;
shortcut.IconLocation = linkIcon ?? sourcePath;
shortcut.WindowStyle = 1;
// shortcut.WorkingDirectory = "";
// shortcut.RelativePath = "";
@ -1067,6 +1071,36 @@ namespace Apewer
#endif
/// <summary>创建 URL 快捷方式,生成 .url 文件。</summary>
/// <param name="linkPath">快捷方式路径,以 .url 结尾。</param>
/// <param name="url">URL。</param>
/// <param name="iconFilePath">快捷方式图标。</param>
/// <param name="iconIndex">快捷方式图标索引。</param>
/// <exception cref="ArgumentNullException" />
public static void CreateUrlShortCut(string linkPath, string url, string iconFilePath = null, int iconIndex = 0)
{
if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath));
if (url.IsEmpty()) throw new ArgumentNullException(nameof(url));
var lines = new List<string>();
lines.Add("[{000214A0-0000-0000-C000-000000000046}]");
lines.Add("Prop3=19,11");
lines.Add("");
lines.Add("[InternetShortcut]");
lines.Add("IDList=");
lines.Add($"URL={url}");
if (StorageUtility.FileExists(iconFilePath))
{
lines.Add($"IconIndex={iconIndex}");
lines.Add("HotKey=0");
lines.Add($"IconFile={iconFilePath}");
}
var text = lines.Join("\r\n") + "\r\n";
var bytes = text.Bytes(Encoding.Default);
StorageUtility.WriteFile(linkPath, bytes);
}
#endregion
}

98
Apewer/Apewer.csproj

@ -1,53 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Apewer\Apewer.props" />
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<Description>实现通用的实用功能。</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net461;net40;net20</TargetFrameworks>
</PropertyGroup>
<!-- .NET Standard 2.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.1'">
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Standard 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Framework 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net20'">
<DefineConstants>NETFX;NET20;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net20'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Framework 4.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net40'">
<DefineConstants>NETFX;NET40;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Framework 4.6.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net461'">
<DefineConstants>NETFX;NET461;NET45;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Core 3.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<DefineConstants>HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<Import Project="..\Apewer\Apewer.props" />
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<Description>实现通用的实用功能。</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.1;net461;net40;net20</TargetFrameworks>
</PropertyGroup>
<!-- .NET Standard 2.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.1'">
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Standard 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Framework 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net20'">
<DefineConstants>NETFX;NET20;DRAWING;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net20'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Framework 4.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net40'">
<DefineConstants>NETFX;NET40;DRAWING;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Framework 4.6.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net461'">
<DefineConstants>NETFX;NET461;NET45;DRAWING;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<!-- .NET Core 3.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<DefineConstants>HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
</Project>

35
Apewer/BytesUtility.cs

@ -271,7 +271,7 @@ namespace Apewer
/// <summary>转换字节数组为文本,默认使用 UTF-8 代码页。</summary>
public static string ToText(byte[] bytes, Encoding encoding = null)
{
if (bytes.Length < 1) return Constant.EmptyString;
if (bytes == null || bytes.Length < 1) return Constant.EmptyString;
try { return (encoding ?? Encoding.UTF8).GetString(bytes); }
catch { return Constant.EmptyString; }
}
@ -464,26 +464,23 @@ namespace Apewer
{
if (files == null) return null;
var output = new MemoryStream();
var input = null as Stream;
var ex = ToZip(files.Keys, output, (name) =>
using (var output = new MemoryStream())
{
RuntimeUtility.Dispose(input);
if (name.IsEmpty()) return null;
var ex = ToZip(files.Keys, output, (name) =>
{
if (name.IsEmpty()) return null;
var bytes = files[name];
if (bytes == null || bytes.LongLength < 1L) return null;
var bytes = files[name];
if (bytes == null || bytes.LongLength < 1L) return null;
input = new MemoryStream();
Write(input, bytes);
return input;
}, null, true);
RuntimeUtility.Dispose(input);
var input = new MemoryStream();
Write(input, bytes);
input.Position = 0;
return input;
}, null, true);
var result = output.ToArray();
RuntimeUtility.Dispose(result);
return result;
return output.ToArray();
}
}
/// <summary>解压 ZIP 文件。</summary>
@ -997,7 +994,7 @@ namespace Apewer
/// <exception cref="CryptographicException" />
public static byte[] AesDecrypt(byte[] cipher, byte[] key, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7)
{
return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV));
return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV));
}
/// <summary>执行 AES 128/192/256 解密。</summary>
@ -1012,7 +1009,7 @@ namespace Apewer
/// <exception cref="CryptographicException" />
public static byte[] AesDecrypt(byte[] cipher, byte[] key, byte[] iv, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7)
{
return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV));
return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV));
}
#endregion

83
Apewer/CollectionUtility.cs

@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
@ -126,6 +127,12 @@ namespace Apewer
}
}
/// <summary>检查当前元素是否存在于集合。</summary>
public static bool In<T>(this T item, IEnumerable<T> collection) => Contains(collection, item);
/// <summary>检查当前元素是否存在于集合。</summary>
public static bool In<T>(this T item, params T[] collection) => Contains(collection, item);
#endregion
#region 类型转换
@ -474,21 +481,71 @@ namespace Apewer
#region 排序
/// <summary>对列表中的元素排序。</summary>
public static List<T> Sort<T>(List<T> list, Func<T, T, int> comparison)
/// <returns>返回排序的数组,用于链式写法。</returns>
/// <exception cref="ArgumentNullException"></exception>
public static List<T> Sort<T>(this List<T> list, params Comparison<T>[] comparisons)
{
if (list == null) return null;
if (comparison == null) return list;
list.Sort(new Comparison<T>(comparison));
if (list == null) throw new ArgumentNullException(nameof(list));
if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
var count = comparisons.Length;
if (count < 1) return list;
for (var i = 0; i < count; i++)
{
if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
}
list.Sort((a, b) =>
{
for (var i = 0; i < count; i++)
{
var compare = comparisons[i].Invoke(a, b);
if (compare != 0) return compare;
}
return Comparer<T>.Default.Compare(a, b);
});
return list;
}
/// <summary>对数组排序。</summary>
/// <exception cref="NullReferenceException"></exception>
public static T[] Sort<T>(T[] array, Func<T, T, int> comparison)
/// <returns>返回排序的数组,用于链式写法。</returns>
/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidOperationException" />
public static T[] Sort<T>(this T[] array)
{
if (array == null) return array;
if (comparison == null) return array;
System.Array.Sort(array, new Comparison<T>(comparison));
System.Array.Sort(array);
return array;
}
/// <summary>对数组排序。</summary>
/// <returns>返回排序的数组,用于链式写法。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException" />
public static T[] Sort<T>(this T[] array, params Comparison<T>[] comparisons)
{
if (array == null) throw new ArgumentNullException(nameof(array));
if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
var count = comparisons.Length;
if (count < 1) return array;
for (var i = 0; i < count; i++)
{
if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
}
System.Array.Sort(array, (a, b) =>
{
for (var i = 0; i < count; i++)
{
var compare = comparisons[i].Invoke(a, b);
if (compare != 0) return compare;
}
return Comparer<T>.Default.Compare(a, b);
});
return array;
}
@ -655,7 +712,7 @@ namespace Apewer
/// <summary>根据条件筛选,将符合条件的元素组成新数组。</summary>
public static T[] FindAll<T>(this IEnumerable<T> collection, Predicate<T> match)
{
if (collection == null) new ArgumentNullException(nameof(collection));
if (collection == null) throw new ArgumentNullException(nameof(collection));
if (match == null) throw new ArgumentNullException(nameof(match));
if (collection is T[] array)
@ -765,7 +822,7 @@ namespace Apewer
if (capacity == count)
{
capacity += 1024;
list.Capacity += capacity;
list.Capacity = capacity;
}
list.Add(selector.Invoke(item, count));
count += 1;
@ -999,7 +1056,7 @@ namespace Apewer
// 生成新数组
var result = new T[array.Length];
for (var i = 0; i < result.Length; i++) result[i] = array[i];
result[index] = value;
result[offset] = value;
return result;
}

123
Apewer/DrawingUtility.cs

@ -0,0 +1,123 @@
#if DRAWING
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace Apewer
{
/// <summary>绘图。</summary>
public static class DrawingUtility
{
/// <summary>优化 Graphics 对象的属性,提升绘图质量。</summary>
public static Graphics Optimize(this Graphics graphics)
{
if (graphics != null)
{
graphics.CompositingMode = CompositingMode.SourceOver;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
}
return graphics;
}
/// <summary>保存图像为文件。</summary>
/// <exception cref="ArgumentNullException"></exception>
public static byte[] Save(this Image image, ImageFormat format)
{
if (image == null) throw new ArgumentNullException(nameof(image));
if (format == null) throw new ArgumentNullException(nameof(format));
using (var memory = new MemoryStream())
{
image.Save(memory, format);
return memory.ToArray();
}
}
/// <summary>保存为 JPEG 文件。</summary>
/// <param name="image">Image 实例。</param>
/// <param name="quality">JPEG 质量,0 为最低质量,100 为最高质量。</param>
/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="System.Runtime.InteropServices.ExternalException" />
public static byte[] SaveAsJpeg(this Image image, int quality = 100)
{
if (image == null) throw new ArgumentNullException(nameof(image));
if (quality < 0 || quality > 100) throw new ArgumentOutOfRangeException(nameof(quality));
var codec = ImageCodecInfo.GetImageDecoders().Find(x => x.FormatID == ImageFormat.Jpeg.Guid);
if (codec == null) throw new System.Runtime.InteropServices.ExternalException($"系统中不存在 JPEG 编码器。");
var parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
using (var memory = new MemoryStream())
{
image.Save(memory, codec, parameters);
return memory.ToArray();
}
}
/// <summary>缩放图像,生成新图像。</summary>
/// <param name="image">原始图像。</param>
/// <param name="size">新图像的大小。</param>
/// <param name="backgroundColor">填充新图像背景色。</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static Bitmap Scale(this Image image, Size size, Color? backgroundColor = null) => Scale(image, size.Width, size.Height, backgroundColor);
/// <summary>缩放图像,生成新图像。</summary>
/// <param name="image">原始图像。</param>
/// <param name="width">新图像的宽度。</param>
/// <param name="height">新图像的高度。</param>
/// <param name="backgroundColor">填充新图像背景色。</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
static Bitmap Scale(this Image image, int width, int height, Color? backgroundColor = null)
{
if (image == null) throw new ArgumentNullException(nameof(image));
if (width < 1) throw new ArgumentOutOfRangeException(nameof(width));
if (height < 1) throw new ArgumentOutOfRangeException(nameof(height));
// 检查原始图像是否为透明格式
var rawFormat = image.RawFormat;
var isTransparentFormat = rawFormat.Equals(ImageFormat.Png) || rawFormat.Equals(ImageFormat.Gif);
var pixelFormat = isTransparentFormat ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb;
var bitmap = new Bitmap(width, height, pixelFormat);
try
{
using (var graphic = Graphics.FromImage(bitmap))
{
graphic.CompositingMode = CompositingMode.SourceOver;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.SmoothingMode = SmoothingMode.AntiAlias;
// 填充背景色
if (isTransparentFormat)
{
if (backgroundColor != null && backgroundColor.HasValue) graphic.Clear(backgroundColor.Value);
}
// 绘制新图像
graphic.DrawImage(image, 0, 0, width, height);
}
return bitmap;
}
catch
{
bitmap.Dispose();
throw;
}
}
}
}
#endif

2
Apewer/Logger.cs

@ -365,7 +365,7 @@ namespace Apewer
if (bytes.Length > 0)
{
var gzipData = BytesUtility.ToGzip(bytes);
if (gzipData != null || gzipData.Length > 0)
if (gzipData != null && gzipData.Length > 0)
{
var gzipPath = path + ".gzip";
StorageUtility.WriteFile(gzipPath, gzipData);

1
Apewer/NumberUtility.cs

@ -428,7 +428,6 @@ namespace Apewer
foreach (var value in values)
{
up += (value - avg) * (value - avg);
count++;
}
}

2
Apewer/Source/Execute.cs

@ -24,7 +24,7 @@ namespace Apewer.Source
/// <summary>创建实例。</summary>
public Execute(bool success, string message)
{
_success = false;
_success = success;
_message = message;
}

2
Apewer/Source/Query.cs

@ -22,7 +22,7 @@ namespace Apewer.Source
/// <summary>创建实例,默认状态为失败。</summary>
public Query(bool success = false, string message = null)
{
_success = false;
_success = success;
_message = message;
}

351
Apewer/Source/SourceUtility.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
namespace Apewer.Source
@ -598,7 +599,6 @@ namespace Apewer.Source
}
}
/// <summary>查询。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
@ -629,6 +629,353 @@ namespace Apewer.Source
}
}
#if !NET20
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <typeparam name="T">元组中的值类型。</typeparam>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue">获取第一个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T>[] Query<T>(this IDbAdo dbClient, string sql, object parameters, Func<object, T> getValue)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue == null) throw new ArgumentNullException(nameof(getValue));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var value1 = getValue(query.Value(i, 0));
tuples[i] = new Tuple<T>(value1);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2>[] Query<T1, T2>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
tuples[i] = new Tuple<T1, T2>(v1, v2);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3>[] Query<T1, T2, T3>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
tuples[i] = new Tuple<T1, T2, T3>(v1, v2, v3);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <param name="getValue4">获取第四个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3, T4>[] Query<T1, T2, T3, T4>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3,
Func<object, T4> getValue4)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3, T4>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
var v4 = getValue4(query.Value(i, 3));
tuples[i] = new Tuple<T1, T2, T3, T4>(v1, v2, v3, v4);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <param name="getValue4">获取第四个值的回调函数。</param>
/// <param name="getValue5">获取第五个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3, T4, T5>[] Query<T1, T2, T3, T4, T5>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3,
Func<object, T4> getValue4,
Func<object, T5> getValue5)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4));
if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3, T4, T5>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
var v4 = getValue4(query.Value(i, 3));
var v5 = getValue5(query.Value(i, 4));
tuples[i] = new Tuple<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <param name="getValue4">获取第四个值的回调函数。</param>
/// <param name="getValue5">获取第五个值的回调函数。</param>
/// <param name="getValue6">获取第六个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3, T4, T5, T6>[] Query<T1, T2, T3, T4, T5, T6>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3,
Func<object, T4> getValue4,
Func<object, T5> getValue5,
Func<object, T6> getValue6)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4));
if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5));
if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3, T4, T5, T6>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
var v4 = getValue4(query.Value(i, 3));
var v5 = getValue5(query.Value(i, 4));
var v6 = getValue6(query.Value(i, 5));
tuples[i] = new Tuple<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <param name="getValue4">获取第四个值的回调函数。</param>
/// <param name="getValue5">获取第五个值的回调函数。</param>
/// <param name="getValue6">获取第六个值的回调函数。</param>
/// <param name="getValue7">获取第七个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3, T4, T5, T6, T7>[] Query<T1, T2, T3, T4, T5, T6, T7>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3,
Func<object, T4> getValue4,
Func<object, T5> getValue5,
Func<object, T6> getValue6,
Func<object, T7> getValue7)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4));
if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5));
if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6));
if (getValue7 == null) throw new ArgumentNullException(nameof(getValue7));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3, T4, T5, T6, T7>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
var v4 = getValue4(query.Value(i, 3));
var v5 = getValue5(query.Value(i, 4));
var v6 = getValue6(query.Value(i, 5));
var v7 = getValue7(query.Value(i, 6));
tuples[i] = new Tuple<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5, v6, v7);
}
return tuples;
}
}
/// <summary>执行查询,将结果输出为元组数组。</summary>
/// <param name="dbClient">数据库连接。</param>
/// <param name="sql">SQL 语句。</param>
/// <param name="parameters">SQL 参数。</param>
/// <param name="getValue1">获取第一个值的回调函数。</param>
/// <param name="getValue2">获取第二个值的回调函数。</param>
/// <param name="getValue3">获取第三个值的回调函数。</param>
/// <param name="getValue4">获取第四个值的回调函数。</param>
/// <param name="getValue5">获取第五个值的回调函数。</param>
/// <param name="getValue6">获取第六个值的回调函数。</param>
/// <param name="getValue7">获取第七个值的回调函数。</param>
/// <param name="getValue8">获取第八个值的回调函数。</param>
/// <returns>由元组组成的数组。</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="SqlException"></exception>
public static Tuple<T1, T2, T3, T4, T5, T6, T7, T8>[] Query<T1, T2, T3, T4, T5, T6, T7, T8>(this IDbAdo dbClient, string sql, object parameters,
Func<object, T1> getValue1,
Func<object, T2> getValue2,
Func<object, T3> getValue3,
Func<object, T4> getValue4,
Func<object, T5> getValue5,
Func<object, T6> getValue6,
Func<object, T7> getValue7,
Func<object, T8> getValue8)
{
if (dbClient == null) throw new ArgumentNullException(nameof(dbClient));
if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql));
if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1));
if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2));
if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3));
if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4));
if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5));
if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6));
if (getValue7 == null) throw new ArgumentNullException(nameof(getValue7));
if (getValue8 == null) throw new ArgumentNullException(nameof(getValue8));
using (var query = dbClient.Query(sql, parameters))
{
if (!query.Success) throw new SqlException(query, sql);
var tuples = new Tuple<T1, T2, T3, T4, T5, T6, T7, T8>[query.Rows];
for (var i = 0; i < query.Rows; i++)
{
var v1 = getValue1(query.Value(i, 0));
var v2 = getValue2(query.Value(i, 1));
var v3 = getValue3(query.Value(i, 2));
var v4 = getValue4(query.Value(i, 3));
var v5 = getValue5(query.Value(i, 4));
var v6 = getValue6(query.Value(i, 5));
var v7 = getValue7(query.Value(i, 6));
var v8 = getValue8(query.Value(i, 7));
tuples[i] = new Tuple<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4, v5, v6, v7, v8);
}
return tuples;
}
}
#endif
#endregion
@ -1268,7 +1615,7 @@ namespace Apewer.Source
#region Dynamic
#if NET40_OR_GREATER
#if !NET20
/// <summary>转换 ObjectSet 数组为 dynamic 数组。</summary>
public static dynamic[] Dynamic(this ObjectSet[] oss)

21
Apewer/Source/SqlException.cs

@ -14,6 +14,7 @@ namespace Apewer.Source
string _msg = null;
string _sql = null;
object _parameters = null;
/// <summary>获取描述当前异常的消息。</summary>
public override string Message { get => _msg; }
@ -21,20 +22,25 @@ namespace Apewer.Source
/// <summary>获取引发异常的 SQL 语句。</summary>
public string Statement { get => _sql; }
/// <summary>获取引发异常的 SQL 参数。</summary>
public object Parameters { get => _parameters; }
/// <summary>初始化 <see cref="SqlException"/> 类的新实例。</summary>
/// <param name="message">描述当前异常的消息。</param>
/// <param name="statement">附带 SQL 语句。</param>
public SqlException(string message, string statement = null)
/// <param name="parameters">附带 SQL 参数。</param>
public SqlException(string message, string statement = null, object parameters = null)
{
_msg = string.IsNullOrEmpty(message) ? EmptyMessage : message;
_sql = statement;
_parameters = parameters;
}
/// <summary>初始化 <see cref="SqlException"/> 类的新实例。</summary>
/// <param name="query">用于获取消息的查询结果。</param>
/// <param name="statement">附带 SQL 语句。</param>
public SqlException(IQuery query, string statement = null)
/// <param name="parameters">附带 SQL 参数。</param>
public SqlException(IQuery query, string statement = null, object parameters = null)
{
if (query == null)
{
@ -44,15 +50,17 @@ namespace Apewer.Source
}
_msg = query.Message;
if (string.IsNullOrEmpty(_msg)) _msg = EmptyMessage;
if (string.IsNullOrEmpty(Message)) _msg = EmptyMessage;
_sql = statement;
_parameters = parameters;
}
/// <summary>初始化 <see cref="SqlException"/> 类的新实例。</summary>
/// <param name="execute">用于获取消息的执行结果。</param>
/// <param name="statement">附带 SQL 语句。</param>
public SqlException(IExecute execute, string statement = null)
/// <param name="parameters">附带 SQL 参数。</param>
public SqlException(IExecute execute, string statement = null, object parameters = null)
{
if (execute == null)
{
@ -61,9 +69,10 @@ namespace Apewer.Source
}
_msg = execute.Message;
if (string.IsNullOrEmpty(_msg)) _msg = EmptyMessage;
if (string.IsNullOrEmpty(Message)) _msg = EmptyMessage;
_sql = statement;
_parameters = parameters;
}
}

2
Apewer/StorageUtility.cs

@ -82,7 +82,7 @@ namespace Apewer
if (!Directory.Exists(path)) return new DirectoryNotFoundException();
var temp = Environment.GetEnvironmentVariable("TEMP");
var name = Path.GetDirectoryName(path);
var name = Path.GetFileName(path);
var dest = null as string;
while (dest == null || Directory.Exists(dest))

5
Apewer/TextUtility.cs

@ -137,7 +137,7 @@ namespace Apewer
if (cell is string) text = cell as string;
else if (cell is Type type) text = type.Name;
else cell.ToString();
else text = cell.ToString();
if (string.IsNullOrEmpty(text)) continue;
if (!first && hasSeparator) sb.Append(separator);
@ -610,7 +610,8 @@ namespace Apewer
// foot
length = text.IndexOf(foot);
if (length < 1) return text;
if (length == 0) return Empty;
if (length < 0) return text;
return text.Substring(0, length);
}
else

3
Apewer/Web/IApiMiddleware.cs

@ -5,7 +5,8 @@
public interface IApiMiddleware
{
/// <summary>调用中间件。</summary>
/// <summary>执行中间件。</summary>
/// <remarks>调用 <see cref="ApiContext.Next" /> 方法可继续处理请求;若不调用则终止请求。</remarks>
void Invoke(ApiContext context);
}

2
Apewer/_Extensions.cs

@ -475,7 +475,7 @@ public static class Extensions
public static T[] Array<T>(IEnumerable<T> @this, bool excludeNull = false) => CollectionUtility.Array<T>(@this, excludeNull);
/// <summary>对列表中的元素排序。</summary>
public static List<T> Sort<T>(this List<T> @this, Func<T, T, int> comparison) => CollectionUtility.Sort(@this, comparison);
public static List<T> Sort<T>(this List<T> @this, Comparison<T> comparison) => CollectionUtility.Sort(@this, comparison);
/// <summary>对字典中的键排序。</summary>
public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(this Dictionary<TKey, TValue> @this, Func<TKey, TKey, int> comparison) => CollectionUtility.SortKey(@this, comparison);

Loading…
Cancel
Save