mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-20 02:16:42 +08:00
发布:3.0.1
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
|
||||
@@ -18,21 +18,25 @@ using System.Linq;
|
||||
namespace TouchSocket.Core.AspNetCore
|
||||
{
|
||||
/// <summary>
|
||||
/// AspNetCoreContainer
|
||||
/// AspNetCoreContainer 类实现了 IRegistrator、IResolver 和 IKeyedServiceProvider 接口,
|
||||
/// 提供了一个容器解决方案,用于在 ASP.NET Core 应用中注册服务和解析服务。
|
||||
/// 它旨在简化依赖注入过程,并支持 keyed 服务的获取。
|
||||
/// </summary>
|
||||
public class AspNetCoreContainer : IRegistrator, IResolver, IKeyedServiceProvider
|
||||
{
|
||||
private readonly IServiceCollection m_services;
|
||||
private IServiceProvider m_serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前对象的IServiceProvider实例。
|
||||
/// </summary>
|
||||
public IServiceProvider ServiceProvider { get => this.m_serviceProvider; }
|
||||
|
||||
//private AspNetCoreResolver m_resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个IServiceCollection的容器。
|
||||
/// 初始化AspNetCoreContainer实例。
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="services">IServiceCollection实例,用于注册服务。</param>
|
||||
public AspNetCoreContainer(IServiceCollection services)
|
||||
{
|
||||
this.m_services = services ?? throw new ArgumentNullException(nameof(services));
|
||||
@@ -41,9 +45,9 @@ namespace TouchSocket.Core.AspNetCore
|
||||
{
|
||||
return;
|
||||
}
|
||||
services.AddSingleton<IResolver>(privoder =>
|
||||
services.AddSingleton<IResolver>(provider =>
|
||||
{
|
||||
this.m_serviceProvider ??= privoder;
|
||||
this.m_serviceProvider ??= provider;
|
||||
return this;
|
||||
});
|
||||
|
||||
@@ -97,7 +101,7 @@ namespace TouchSocket.Core.AspNetCore
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.ServiceType == fromType&&item.ServiceKey?.ToString()==key)
|
||||
if (item.ServiceType == fromType && item.ServiceKey?.ToString() == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace TouchSocket.Core
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将输入字符串转换为有效的标识符。
|
||||
/// </summary>
|
||||
/// <param name="input">输入字符串。</param>
|
||||
/// <returns>转换后的标识符字符串。</returns>
|
||||
public static string MakeIdentifier(string input)
|
||||
{
|
||||
// 替换非法字符
|
||||
|
||||
@@ -25,31 +25,73 @@ namespace TouchSocket.Core
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, Dictionary<string, Property>> m_typeToProperty = new ConcurrentDictionary<Type, Dictionary<string, Property>>();
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将源对象映射到指定目标类型的新实例。
|
||||
/// </summary>
|
||||
/// <param name="source">源对象,其属性将被映射到目标类型。</param>
|
||||
/// <param name="option">映射选项,用于自定义映射行为。</param>
|
||||
/// <typeparam name="TTarget">要映射到的目标类型。</typeparam>
|
||||
/// <returns>一个新创建的目标类型实例,其属性根据源对象的属性值进行映射。</returns>
|
||||
public static TTarget Map<TTarget>(this object source, MapperOption option = default) where TTarget : class, new()
|
||||
{
|
||||
// 调用泛型方法 Map,将源对象、目标类型和映射选项传递给它
|
||||
// 由于目标类型的实例化和类型转换由 Map 方法内部处理,这里直接返回转换后的结果
|
||||
return (TTarget)Map(source, typeof(TTarget), option);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 扩展方法,用于将对象映射到相同类型的另一个对象。
|
||||
/// </summary>
|
||||
/// <param name="source">要映射的源对象。</param>
|
||||
/// <param name="option">映射选项,用于定制映射行为。</param>
|
||||
/// <typeparam name="TTarget">源对象和目标对象的类型。</typeparam>
|
||||
/// <returns>返回映射后的目标对象。</returns>
|
||||
public static TTarget Map<TTarget>(this TTarget source, MapperOption option = default) where TTarget : class, new()
|
||||
{
|
||||
// 调用泛型方法 Map,将源对象映射为目标对象
|
||||
return (TTarget)Map(source, typeof(TTarget), option);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 扩展方法,用于将一个对象映射到另一个类型。
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源对象的类型。</typeparam>
|
||||
/// <typeparam name="TTarget">目标对象的类型,必须是引用类型且有默认构造函数。</typeparam>
|
||||
/// <param name="source">要映射的源对象。</param>
|
||||
/// <param name="option">映射选项,用于控制映射行为。</param>
|
||||
/// <returns>返回映射后的目标对象实例。</returns>
|
||||
public static TTarget Map<TSource, TTarget>(this TSource source, MapperOption option = default) where TTarget : class, new()
|
||||
{
|
||||
// 调用泛型映射方法,将源对象、目标类型和映射选项传递给它
|
||||
// 由于目标类型在运行时才能确定,这里使用反射来动态调用合适的映射方法
|
||||
return (TTarget)Map(source, typeof(TTarget), option);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将源对象映射到目标类型的实例。
|
||||
/// </summary>
|
||||
/// <param name="source">要映射的源对象。</param>
|
||||
/// <param name="targetType">目标类型的 <see cref="Type"/>。</param>
|
||||
/// <param name="option">映射选项,用于控制映射行为。</param>
|
||||
/// <returns>映射后的目标类型实例。</returns>
|
||||
public static object Map(this object source, Type targetType, MapperOption option = default)
|
||||
{
|
||||
// 使用 Activator.CreateInstance 创建目标类型的实例,并将源对象映射到该实例
|
||||
return Map(source, Activator.CreateInstance(targetType), option);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将源对象的属性映射到目标对象的属性中。
|
||||
/// </summary>
|
||||
/// <param name="source">源对象,其属性将被映射。</param>
|
||||
/// <param name="target">目标对象,将接收映射的属性值。</param>
|
||||
/// <param name="option">映射选项,用于定制映射行为。</param>
|
||||
/// <returns>返回映射后的目标对象。</returns>
|
||||
public static object Map(this object source, object target, MapperOption option = default)
|
||||
{
|
||||
if (source is null)
|
||||
@@ -109,35 +151,60 @@ namespace TouchSocket.Core
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 扩展方法,将一个泛型集合中的每个元素映射到另一个泛型类型的新集合。
|
||||
/// </summary>
|
||||
/// <param name="list">要映射的原始集合。</param>
|
||||
/// <param name="option">映射选项,用于自定义映射行为。</param>
|
||||
/// <typeparam name="T">原始集合中的元素类型。</typeparam>
|
||||
/// <typeparam name="T1">目标集合中的元素类型。</typeparam>
|
||||
/// <returns>一个新集合,包含原始集合中每个元素的映射结果。</returns>
|
||||
public static IEnumerable<T1> MapList<T, T1>(this IEnumerable<T> list, MapperOption option = default) where T : class where T1 : class, new()
|
||||
{
|
||||
// 检查输入的集合是否为null,如果是,则抛出异常
|
||||
if (list is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(list));
|
||||
}
|
||||
|
||||
// 初始化结果集合,用于存储映射后的元素
|
||||
var result = new List<T1>();
|
||||
// 遍历原始集合中的每个元素
|
||||
foreach (var item in list)
|
||||
{
|
||||
// 将当前元素映射到目标类型,并将结果添加到结果集合中
|
||||
result.Add(Map<T, T1>(item, option));
|
||||
}
|
||||
// 返回结果集合
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将对象集合映射为指定类型的集合。
|
||||
/// </summary>
|
||||
/// <param name="list">待映射的对象集合。</param>
|
||||
/// <param name="option">映射选项。</param>
|
||||
/// <typeparam name="T1">目标类型。</typeparam>
|
||||
/// <returns>映射后的指定类型的集合。</returns>
|
||||
public static IEnumerable<T1> MapList<T1>(this IEnumerable<object> list, MapperOption option = default) where T1 : class, new()
|
||||
{
|
||||
// 检查输入集合是否为null,如果是,则抛出异常
|
||||
if (list is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(list));
|
||||
}
|
||||
|
||||
// 初始化结果集合
|
||||
var result = new List<T1>();
|
||||
// 遍历输入集合中的每个对象
|
||||
foreach (var item in list)
|
||||
{
|
||||
// 将当前对象映射为目标类型,并添加到结果集合中
|
||||
result.Add(Map<T1>(item, option));
|
||||
}
|
||||
// 返回结果集合
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ namespace TouchSocket.Core
|
||||
/// <summary>
|
||||
/// 获取已添加的指定名称的插件数量。
|
||||
/// </summary>
|
||||
/// <param name="interfeceType"></param>
|
||||
/// <param name="pluginType"></param>
|
||||
/// <returns></returns>
|
||||
int GetPluginCount(Type interfeceType);
|
||||
int GetPluginCount(Type pluginType);
|
||||
|
||||
/// <summary>
|
||||
/// 所包含的所有插件。
|
||||
@@ -44,24 +44,36 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <param name="plugin">插件</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
void Add<[DynamicallyAccessedMembers(PluginManagerExtension.PluginAccessedMemberTypes)]TPlugin>(TPlugin plugin)where TPlugin:class,IPlugin;
|
||||
void Add<[DynamicallyAccessedMembers(PluginManagerExtension.PluginAccessedMemberTypes)] TPlugin>(TPlugin plugin) where TPlugin : class, IPlugin;
|
||||
|
||||
|
||||
void Add(Type interfeceType, Func<object, PluginEventArgs, Task> pluginInvokeHandler,Delegate sourceDelegate=default);
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个插件类型及其对应的调用处理程序。
|
||||
/// </summary>
|
||||
/// <param name="pluginType">插件的类型。</param>
|
||||
/// <param name="pluginInvokeHandler">插件调用处理程序,当插件被调用时执行。</param>
|
||||
/// <param name="sourceDelegate">可选的源委托,用于标识插件的来源。</param>
|
||||
void Add(Type pluginType, Func<object, PluginEventArgs, Task> pluginInvokeHandler, Delegate sourceDelegate = default);
|
||||
|
||||
/// <summary>
|
||||
/// 触发对应插件
|
||||
/// </summary>
|
||||
/// <param name="interfeceType"></param>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <param name="pluginType">插件接口类型</param>
|
||||
/// <param name="sender">事件发送者</param>
|
||||
/// <param name="e">事件参数</param>
|
||||
/// <returns>表示在执行的插件中,是否处理<see cref="TouchSocketEventArgs.Handled"/>为<see langword="true"/>。</returns>
|
||||
ValueTask<bool> RaiseAsync(Type interfeceType, object sender, PluginEventArgs e);
|
||||
ValueTask<bool> RaiseAsync(Type pluginType, object sender, PluginEventArgs e);
|
||||
/// <summary>
|
||||
/// 移除指定的插件实例
|
||||
/// </summary>
|
||||
/// <param name="plugin">要移除的插件实例</param>
|
||||
void Remove(IPlugin plugin);
|
||||
void Remove(Type interfeceType, Delegate func);
|
||||
|
||||
//void Add<TSender, TEventArgs>(Type interfeceType, Func<TSender, TEventArgs, Task> func)
|
||||
// where TSender:class
|
||||
// where TEventArgs : PluginEventArgs;
|
||||
/// <summary>
|
||||
/// 根据插件类型和功能委托移除插件
|
||||
/// </summary>
|
||||
/// <param name="pluginType">要移除的插件类型</param>
|
||||
/// <param name="func">代表要移除的功能的委托</param>
|
||||
void Remove(Type pluginType, Delegate func);
|
||||
}
|
||||
}
|
||||
@@ -22,17 +22,39 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
public static class PluginManagerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件访问成员类型,用于指定动态访问的成员类型。
|
||||
/// </summary>
|
||||
public const DynamicallyAccessedMemberTypes PluginAccessedMemberTypes = DynamicallyAccessedMemberTypes.All;
|
||||
|
||||
/// <summary>
|
||||
/// 向插件管理器中添加一个指定类型的插件。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器实例。</param>
|
||||
/// <param name="func">一个函数,用于通过解析器创建插件实例。</param>
|
||||
/// <typeparam name="TPlugin">要添加的插件类型。</typeparam>
|
||||
/// <returns>返回添加到插件管理器中的插件实例。</returns>
|
||||
public static TPlugin Add<[DynamicallyAccessedMembers(PluginAccessedMemberTypes)] TPlugin>(this IPluginManager pluginManager, Func<IResolver, TPlugin> func) where TPlugin : class, IPlugin
|
||||
{
|
||||
// 检查传入的函数是否为null,并抛出异常
|
||||
ThrowHelper.ThrowArgumentNullExceptionIf(func, nameof(func));
|
||||
|
||||
// 使用提供的函数和插件管理器的解析器来创建插件实例
|
||||
var plugin = func.Invoke(pluginManager.Resolver);
|
||||
|
||||
// 将创建的插件实例添加到插件管理器中
|
||||
pluginManager.Add(plugin);
|
||||
|
||||
// 返回创建的插件实例
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器添加插件类型。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器实例,允许通过其调用扩展方法。</param>
|
||||
/// <param name="pluginType">要添加的插件类型,该类型应包含特定的成员以供插件系统访问。</param>
|
||||
/// <returns>返回添加插件类型后的插件管理器实例。</returns>
|
||||
public static object Add(this IPluginManager pluginManager, [DynamicallyAccessedMembers(PluginAccessedMemberTypes)] Type pluginType)
|
||||
{
|
||||
if (pluginType.GetCustomAttribute<PluginOptionAttribute>() is PluginOptionAttribute optionAttribute)
|
||||
@@ -81,64 +103,123 @@ namespace TouchSocket.Core
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public static void Add<TSender, TEventArgs>(this IPluginManager pluginManager, Type interfeceType, Func<TSender, TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器添加一个新的事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器接口,用于管理插件的加载和事件处理函数的注册。</param>
|
||||
/// <param name="interfaceType">插件接口类型,用于指定该事件处理函数将关联的插件类型。</param>
|
||||
/// <param name="func">异步事件处理函数,接受事件发送者和事件参数作为输入,并返回一个任务。</param>
|
||||
/// <typeparam name="TSender">事件发送者的类型。</typeparam>
|
||||
/// <typeparam name="TEventArgs">事件参数的类型,必须继承自PluginEventArgs。</typeparam>
|
||||
public static void Add<TSender, TEventArgs>(this IPluginManager pluginManager, Type interfaceType, Func<TSender, TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
{
|
||||
// 创建一个新的任务,封装了传入的事件处理函数,以适应插件管理器所需的参数类型。
|
||||
Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
// 调用传入的事件处理函数,传入转换后的参数。
|
||||
return func((TSender)sender, (TEventArgs)e);
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, func);
|
||||
|
||||
// 调用插件管理器的Add方法,注册新的事件处理函数。
|
||||
pluginManager.Add(interfaceType, newFunc, func);
|
||||
}
|
||||
|
||||
public static void Add<TEventArgs>(this IPluginManager pluginManager, Type interfeceType, Func<TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器添加一个新的事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器接口,用于添加事件处理函数。</param>
|
||||
/// <param name="interfaceType">插件接口的类型,用于指定事件处理函数关联的插件类型。</param>
|
||||
/// <param name="func">要添加的事件处理函数,当事件触发时将异步执行此函数。</param>
|
||||
/// <typeparam name="TEventArgs">事件参数的类型,必须继承自PluginEventArgs。</typeparam>
|
||||
public static void Add<TEventArgs>(this IPluginManager pluginManager, Type interfaceType, Func<TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
{
|
||||
// 创建一个新的任务,封装传入的事件处理函数,使其与插件管理器期望的签名匹配。
|
||||
Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
// 转换基础PluginEventArgs为具体的TEventArgs类型,然后调用传入的事件处理函数。
|
||||
return func((TEventArgs)e);
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, func);
|
||||
// 调用插件管理器的Add方法,注册新的事件处理函数。
|
||||
pluginManager.Add(interfaceType, newFunc, func);
|
||||
}
|
||||
|
||||
public static void Add(this IPluginManager pluginManager, Type interfeceType, Func<Task> func)
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器中添加一个新的插件。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器实例,用于添加插件。</param>
|
||||
/// <param name="interfaceType">插件需要实现的接口类型。</param>
|
||||
/// <param name="func">插件的具体逻辑,作为一个异步任务执行。</param>
|
||||
public static void Add(this IPluginManager pluginManager, Type interfaceType, Func<Task> func)
|
||||
{
|
||||
// 定义一个新的异步任务,封装传入的插件逻辑和插件链的继续执行
|
||||
async Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
// 执行传入的插件逻辑,不捕获当前上下文
|
||||
await func().ConfigureAwait(false);
|
||||
// 继续执行插件链中的下一个插件,不捕获当前上下文
|
||||
await e.InvokeNext().ConfigureAwait(false);
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, func);
|
||||
|
||||
// 将封装后的插件逻辑添加到插件管理器中
|
||||
pluginManager.Add(interfaceType, newFunc, func);
|
||||
}
|
||||
|
||||
public static void Add<T>(this IPluginManager pluginManager, Type interfeceType, Action<T> action) where T : class
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器添加新插件。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器接口,用于添加插件。</param>
|
||||
/// <param name="interfaceType">插件需要实现的接口类型。</param>
|
||||
/// <param name="action">插件被调用时执行的操作。</param>
|
||||
/// <typeparam name="T">插件的类型,必须是类类型。</typeparam>
|
||||
public static void Add<T>(this IPluginManager pluginManager, Type interfaceType, Action<T> action) where T : class
|
||||
{
|
||||
// 判断泛型类型T是否继承自PluginEventArgs
|
||||
if (typeof(PluginEventArgs).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
// 如果T是PluginEventArgs的子类,则定义一个新的异步任务处理方法
|
||||
async Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
// 执行传入的action,这里将e转换为T类型
|
||||
action(e as T);
|
||||
// 调用下一个插件,确保插件链的执行顺序
|
||||
await e.InvokeNext().ConfigureAwait(false);
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, action);
|
||||
// 将新定义的处理方法添加到插件管理器中
|
||||
pluginManager.Add(interfaceType, newFunc, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果T不是PluginEventArgs的子类,则定义另一个异步任务处理方法
|
||||
async Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
// 执行传入的action,这里将sender转换为T类型
|
||||
action((T)sender);
|
||||
// 调用下一个插件,确保插件链的执行顺序
|
||||
await e.InvokeNext().ConfigureAwait(false);
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, action);
|
||||
// 将新定义的处理方法添加到插件管理器中
|
||||
pluginManager.Add(interfaceType, newFunc, action);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(this IPluginManager pluginManager, Type interfeceType, Action action)
|
||||
/// <summary>
|
||||
/// 扩展方法,用于向插件管理器中添加一个新的插件处理程序。
|
||||
/// </summary>
|
||||
/// <param name="pluginManager">插件管理器实例,允许通过扩展方法语法调用此方法。</param>
|
||||
/// <param name="interfaceType">插件所实现的接口类型,用于标识和分类插件。</param>
|
||||
/// <param name="action">插件处理程序将要执行的动作。</param>
|
||||
public static void Add(this IPluginManager pluginManager, Type interfaceType, Action action)
|
||||
{
|
||||
// 创建一个新的异步处理程序,它将在插件事件被触发时执行指定的动作,
|
||||
// 并在动作完成后调用事件的InvokeNext方法以继续执行下一个插件处理程序。
|
||||
async Task newFunc(object sender, PluginEventArgs e)
|
||||
{
|
||||
action();
|
||||
await e.InvokeNext().ConfigureAwait(false);
|
||||
action(); // 执行插件处理程序指定的动作。
|
||||
await e.InvokeNext().ConfigureAwait(false); // 继续执行下一个插件处理程序。
|
||||
}
|
||||
pluginManager.Add(interfeceType, newFunc, action);
|
||||
|
||||
// 调用插件管理器的Add方法,注册新的异步处理程序和动作。
|
||||
pluginManager.Add(interfaceType, newFunc, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,12 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class| AttributeTargets.Struct| AttributeTargets.Method| AttributeTargets.Interface)]
|
||||
/// <summary>
|
||||
/// 定义一个动态方法的特性,可以指导源生代码生成器如何生成动态方法。便于在运行时动态调用。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface)]
|
||||
public sealed class DynamicMethodAttribute : Attribute
|
||||
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义一个类 JsonMemoryToClassSerializerFormatter,用于将只读内存中的字节序列反序列化为指定的状态类。
|
||||
/// 该类实现了 ISerializerFormatter 接口,特化于 ReadOnlyMemory{byte} 类型的输入和 TState 类型的输出。
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">要反序列化的状态类类型。</typeparam>
|
||||
public class JsonMemoryToClassSerializerFormatter<TState> : ISerializerFormatter<ReadOnlyMemory<byte>, TState>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,8 +20,10 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
public JsonSerializerSettings JsonSettings { get; set; } = new JsonSerializerSettings();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryDeserialize(TState state, in ReadOnlyMemory<byte> source, Type targetType, out object target)
|
||||
{
|
||||
try
|
||||
@@ -31,6 +38,7 @@ namespace TouchSocket.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TrySerialize(TState state, in object target, out ReadOnlyMemory<byte> source)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -30,8 +30,15 @@ namespace TouchSocket.Dmtp
|
||||
registrator.RegisterSingleton<IDmtpRouteService, DmtpRouteService>();
|
||||
}
|
||||
|
||||
public static void AddDmtpRouteService<TDmtpRouteService>(this IRegistrator registrator)where TDmtpRouteService :class, IDmtpRouteService
|
||||
/// <summary>
|
||||
/// 扩展方法用于在服务容器中注册DMTP路由服务的单例实例。
|
||||
/// </summary>
|
||||
/// <typeparam name="TDmtpRouteService">DMTP路由服务的具体类型。</typeparam>
|
||||
/// <param name="registrator">服务注册器接口,用于在服务容器中注册服务。</param>
|
||||
public static void AddDmtpRouteService<TDmtpRouteService>(this IRegistrator registrator)
|
||||
where TDmtpRouteService : class, IDmtpRouteService
|
||||
{
|
||||
// 使用单例模式注册DMTP路由服务,确保在整个应用生命周期中只创建一个实例。
|
||||
registrator.RegisterSingleton<IDmtpRouteService, TDmtpRouteService>();
|
||||
}
|
||||
|
||||
@@ -51,13 +58,16 @@ namespace TouchSocket.Dmtp
|
||||
/// <summary>
|
||||
/// 添加基于设定委托的Dmtp路由服务。
|
||||
/// </summary>
|
||||
/// <param name="registrator"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="registrator">服务注册器接口,用于注册服务。</param>
|
||||
/// <param name="action">一个函数委托,根据ID返回一个IDmtpActor实例。</param>
|
||||
public static void AddDmtpRouteService(this IRegistrator registrator, Func<string, IDmtpActor> action)
|
||||
{
|
||||
// 调用重载版本的AddDmtpRouteService方法,处理异步操作
|
||||
AddDmtpRouteService(registrator, async (id) =>
|
||||
{
|
||||
// 完成一个已经完成的任务,用于简化异步操作
|
||||
await EasyTask.CompletedTask;
|
||||
// 调用传入的委托,并返回结果
|
||||
return action.Invoke(id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace TouchSocket.Http
|
||||
/// <param name="response">Http响应</param>
|
||||
public HttpContext(HttpRequest request, HttpResponse response)
|
||||
{
|
||||
this.Request = request ?? throw new ArgumentNullException(nameof(request));
|
||||
this.Response = response ?? throw new ArgumentNullException(nameof(response));
|
||||
this.Request = request;
|
||||
this.Response = response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace TouchSocket.Http
|
||||
/// 构建数据并回应。
|
||||
/// <para>该方法仅在具有Client实例时有效。</para>
|
||||
/// </summary>
|
||||
public async Task AnswerAsync(CancellationToken token=default)
|
||||
public async Task AnswerAsync(CancellationToken token = default)
|
||||
{
|
||||
this.ThrowIfResponsed();
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace TouchSocket.Http
|
||||
this.Responsed = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当传输模式是Chunk时,用于结束传输。
|
||||
@@ -219,7 +219,7 @@ namespace TouchSocket.Http
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -258,6 +258,11 @@ namespace TouchSocket.Http
|
||||
|
||||
#region Write
|
||||
|
||||
/// <summary>
|
||||
/// 异步写入指定的只读内存数据。
|
||||
/// </summary>
|
||||
/// <param name="memory">要写入的只读内存数据。</param>
|
||||
/// <returns>一个任务,表示异步写入操作。</returns>
|
||||
public async Task WriteAsync(ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
this.ThrowIfResponsed();
|
||||
@@ -371,10 +376,10 @@ namespace TouchSocket.Http
|
||||
{
|
||||
this.Headers.Add(HttpHeaders.TransferEncoding, "chunked");
|
||||
}
|
||||
foreach (var headerkey in this.Headers.Keys)
|
||||
foreach (var headerKey in this.Headers.Keys)
|
||||
{
|
||||
stringBuilder.Append($"{headerkey}: ");
|
||||
stringBuilder.Append(this.Headers[headerkey] + "\r\n");
|
||||
stringBuilder.Append($"{headerKey}: ");
|
||||
stringBuilder.Append(this.Headers[headerKey] + "\r\n");
|
||||
}
|
||||
|
||||
stringBuilder.Append("\r\n");
|
||||
|
||||
@@ -121,8 +121,18 @@ namespace TouchSocket.Http
|
||||
#endregion Download
|
||||
|
||||
#region Upload
|
||||
|
||||
/// <summary>
|
||||
/// 异步上传文件到指定URL。
|
||||
/// </summary>
|
||||
/// <param name="client">HttpClient实例,用于发送HTTP请求。</param>
|
||||
/// <param name="url">文件上传的URL地址。</param>
|
||||
/// <param name="fileInfo">包含文件信息的FileInfo对象,用于获取文件内容和属性。</param>
|
||||
/// <param name="millisecondsTimeout">请求的超时时间,默认为10秒。如果在此时间内未完成上传,请求将被取消。</param>
|
||||
/// <param name="token">用于取消操作的取消令牌。</param>
|
||||
/// <typeparam name="TClient">客户端类型,必须继承自HttpClientBase并实现IHttpClient接口。</typeparam>
|
||||
public static async Task UploadFileAsync<TClient>(this TClient client, string url, FileInfo fileInfo, int millisecondsTimeout = 10 * 1000, CancellationToken token = default)
|
||||
where TClient : HttpClientBase,IHttpClient
|
||||
where TClient : HttpClientBase, IHttpClient
|
||||
{
|
||||
//创建一个请求
|
||||
var request = new HttpRequest();
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace TouchSocket.Http
|
||||
/// <returns>返回一个只读内存块,该内存块包含具体的字节内容。</returns>
|
||||
/// <param name="httpBase"></param>
|
||||
/// <param name="cancellationToken">一个CancellationToken对象,用于取消异步操作。</param>
|
||||
public static ReadOnlyMemory<byte> GetContent(this HttpBase httpBase,CancellationToken cancellationToken = default)
|
||||
public static ReadOnlyMemory<byte> GetContent(this HttpBase httpBase, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 使用Task.Run来启动一个新的任务,该任务将异步地获取内容。
|
||||
// 这里使用GetFalseAwaitResult()方法来处理任务的结果,确保即使在同步上下文中也能正确处理异常。
|
||||
@@ -166,9 +166,17 @@ namespace TouchSocket.Http
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为HttpBase类型对象设置内容。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">泛型参数T,表示HttpBase类型或其派生类型。</typeparam>
|
||||
/// <param name="httpBase">需要设置内容的HttpBase类型对象。</param>
|
||||
/// <param name="content">要设置的内容,类型为HttpContent。</param>
|
||||
/// <returns>返回设置内容后的HttpBase对象。</returns>
|
||||
public static T SetContent<T>(this T httpBase, HttpContent content) where T : HttpBase
|
||||
{
|
||||
httpBase.Content= content;
|
||||
// 将传入的内容设置到HttpBase对象中
|
||||
httpBase.Content = content;
|
||||
// 返回处理后的HttpBase对象
|
||||
return httpBase;
|
||||
}
|
||||
@@ -234,13 +242,27 @@ namespace TouchSocket.Http
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个键值对集合按照application/x-www-form-urlencoded格式设置到HttpRequest的内容中
|
||||
/// </summary>
|
||||
/// <param name="request">待设置内容的HttpRequest对象</param>
|
||||
/// <param name="nameValueCollection">包含键值对的集合,将被转换为查询字符串格式</param>
|
||||
/// <typeparam name="TRequest">HttpRequest的类型,使用泛型以支持所有HttpRequest的子类</typeparam>
|
||||
public static void SetFormUrlEncodedContent<TRequest>(this TRequest request, IEnumerable<KeyValuePair<string, string>> nameValueCollection)
|
||||
where TRequest : HttpRequest
|
||||
{
|
||||
// 将键值对集合转换为查询字符串格式,并设置为请求的内容
|
||||
request.SetContent(string.Join("&", nameValueCollection.Select(a => $"{a.Key}={a.Value}")));
|
||||
// 设置请求的内容类型为application/x-www-form-urlencoded
|
||||
request.ContentType = "application/x-www-form-urlencoded";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取HttpRequest的表单集合
|
||||
/// </summary>
|
||||
/// <param name="request">HttpRequest对象,用于提取表单数据</param>
|
||||
/// <typeparam name="TRequest">泛型参数,限定为HttpRequest类型</typeparam>
|
||||
/// <returns>返回一个任务,该任务的结果是IFormCollection类型的表单集合</returns>
|
||||
public static async Task<IFormCollection> GetFormCollectionAsync<TRequest>(this TRequest request) where TRequest : HttpRequest
|
||||
{
|
||||
// 检查请求中是否包含分隔符,这是判断是否存在多文件数据的依据。
|
||||
|
||||
@@ -67,19 +67,41 @@ namespace TouchSocket.Http
|
||||
/// <returns>返回一个任务对象,代表异步写入操作</returns>
|
||||
protected abstract Task WriteContent(Func<ReadOnlyMemory<byte>, Task> writeFunc, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 将字符串内容隐式转换为HttpContent对象,使用UTF-8编码。
|
||||
/// </summary>
|
||||
/// <param name="content">要转换的字符串内容。</param>
|
||||
/// <returns>一个新的StringHttpContent对象。</returns>
|
||||
public static implicit operator HttpContent(string content)
|
||||
{
|
||||
return new StringHttpContent(content,Encoding.UTF8);
|
||||
return new StringHttpContent(content, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将只读内存字节内容隐式转换为HttpContent对象。
|
||||
/// </summary>
|
||||
/// <param name="content">要转换的只读内存字节内容。</param>
|
||||
/// <returns>一个新的ReadonlyMemoryHttpContent对象。</returns>
|
||||
public static implicit operator HttpContent(ReadOnlyMemory<byte> content)
|
||||
{
|
||||
return new ReadonlyMemoryHttpContent(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字节数组内容隐式转换为HttpContent对象。
|
||||
/// </summary>
|
||||
/// <param name="content">要转换的字节数组内容。</param>
|
||||
/// <returns>一个新的ReadonlyMemoryHttpContent对象。</returns>
|
||||
public static implicit operator HttpContent(byte[] content)
|
||||
{
|
||||
return new ReadonlyMemoryHttpContent(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将流内容隐式转换为HttpContent对象。
|
||||
/// </summary>
|
||||
/// <param name="content">要转换的流内容。</param>
|
||||
/// <returns>一个新的StreamHttpContent对象。</returns>
|
||||
public static implicit operator HttpContent(Stream content)
|
||||
{
|
||||
return new StreamHttpContent(content);
|
||||
|
||||
@@ -14,6 +14,10 @@ namespace TouchSocket.Http
|
||||
{
|
||||
private readonly ReadOnlyMemory<byte> m_memory;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="ReadonlyMemoryHttpContent"/> 类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="memory">要封装的只读内存。</param>
|
||||
public ReadonlyMemoryHttpContent(ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
this.m_memory = memory;
|
||||
@@ -26,7 +30,7 @@ namespace TouchSocket.Http
|
||||
{
|
||||
return true;//直接构建成功,也不用调用后续的WriteContent
|
||||
}
|
||||
if (byteBlock.FreeLength>this.m_memory.Length)
|
||||
if (byteBlock.FreeLength > this.m_memory.Length)
|
||||
{
|
||||
//如果空闲空间足够,构建成功,也不用调用后续的WriteContent
|
||||
byteBlock.Write(this.m_memory.Span);
|
||||
@@ -40,7 +44,7 @@ namespace TouchSocket.Http
|
||||
/// <inheritdoc/>
|
||||
protected override void OnBuildingHeader(IHttpHeader header)
|
||||
{
|
||||
header.Add(HttpHeaders.ContentLength,this.m_memory.Length.ToString());
|
||||
header.Add(HttpHeaders.ContentLength, this.m_memory.Length.ToString());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -9,29 +9,44 @@ using TouchSocket.Core;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 继承自HttpContent的类,用于将Stream数据转换为可发送的HTTP内容。
|
||||
/// </summary>
|
||||
public class StreamHttpContent : HttpContent
|
||||
{
|
||||
private readonly int m_bufferLength;
|
||||
private readonly int m_maxSpeed;
|
||||
private readonly Stream m_stream;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化StreamHttpContent类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="stream">要包装的流。</param>
|
||||
/// <param name="bufferLength">读取数据时使用的缓冲区长度,默认为64KB。</param>
|
||||
/// <param name="maxSpeed">传输内容的最大速度,默认为Int32最大值,表示不限速。</param>
|
||||
public StreamHttpContent(Stream stream, int bufferLength = 1024 * 64, int maxSpeed = int.MaxValue)
|
||||
{
|
||||
// 将提供的流分配给内部变量m_stream
|
||||
this.m_stream = stream;
|
||||
// 将提供的缓冲区长度分配给内部变量m_bufferLength
|
||||
this.m_bufferLength = bufferLength;
|
||||
// 将提供的最大速度分配给内部变量m_maxSpeed
|
||||
this.m_maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool OnBuildingContent<TByteBlock>(ref TByteBlock byteBlock)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnBuildingHeader(IHttpHeader header)
|
||||
{
|
||||
header.Add(HttpHeaders.ContentLength, this.m_stream.Length.ToString());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task WriteContent(Func<ReadOnlyMemory<byte>, Task> writeFunc, CancellationToken token)
|
||||
{
|
||||
Memory<byte> memory = new byte[this.m_bufferLength];
|
||||
|
||||
@@ -6,11 +6,23 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示以字符串形式存储的 HTTP 内容。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该类继承自 ReadonlyMemoryHttpContent,用于处理只读的内存中 HTTP 内容。
|
||||
/// 它将字符串内容转换为字节数组,并传递给基类以进行处理。
|
||||
/// </remarks>
|
||||
public class StringHttpContent : ReadonlyMemoryHttpContent
|
||||
{
|
||||
public StringHttpContent(string content,Encoding encoding) : base(encoding.GetBytes(content))
|
||||
/// <summary>
|
||||
/// 初始化 StringHttpContent 类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="content">要包含的字符串内容。</param>
|
||||
/// <param name="encoding">用于将字符串内容编码为字节数组的编码方式。</param>
|
||||
public StringHttpContent(string content, Encoding encoding) : base(encoding.GetBytes(content))
|
||||
{
|
||||
|
||||
// 构造函数将字符串内容和编码方式作为参数,将字符串内容转换为字节数组后传递给基类。
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,53 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个键值对集合,通常用于表示HTTP表单中的数据
|
||||
/// </summary>
|
||||
public interface IFormCollection : IEnumerable<KeyValuePair<string, string>>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取集合中键值对的数量
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取包含上传文件的集合
|
||||
/// </summary>
|
||||
IMultifileCollection Files { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取集合中所有键的集合
|
||||
/// </summary>
|
||||
ICollection<string> Keys { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据键获取对应的值
|
||||
/// </summary>
|
||||
/// <param name="key">要获取值的键</param>
|
||||
/// <returns>与指定键关联的值</returns>
|
||||
string this[string key] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据键获取对应的值
|
||||
/// </summary>
|
||||
/// <param name="key">要获取的键</param>
|
||||
/// <returns>与指定键关联的值</returns>
|
||||
string Get(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 判断集合中是否包含指定的键
|
||||
/// </summary>
|
||||
/// <param name="key">要检查的键</param>
|
||||
/// <returns>如果集合包含指定的键,则返回true;否则返回false</returns>
|
||||
bool ContainsKey(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 尝试根据键获取对应的值
|
||||
/// </summary>
|
||||
/// <param name="key">要获取值的键</param>
|
||||
/// <param name="value">与指定键关联的值,如果键不存在则为null</param>
|
||||
/// <returns>如果键存在于集合中,则返回true;否则返回false</returns>
|
||||
bool TryGetValue(string key, out string value);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,12 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
{
|
||||
public interface IMultifileCollection: IEnumerable<IFormFile>
|
||||
/// <summary>
|
||||
/// 定义一个多文件集合接口,继承自IEnumerable{IFormFile}。
|
||||
/// 此接口用于统一处理多个文件的集合,提供了遍历集合中每个文件的能力。
|
||||
/// </summary>
|
||||
public interface IMultifileCollection : IEnumerable<IFormFile>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,17 +200,30 @@ namespace TouchSocket.NamedPipe
|
||||
return this.ProtectedResetIdAsync(newId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 中止当前操作,并安全地关闭相关资源。
|
||||
/// </summary>
|
||||
/// <param name="manual">指示中止操作是否是手动触发的。</param>
|
||||
/// <param name="msg">中止操作的消息说明。</param>
|
||||
protected void Abort(bool manual, string msg)
|
||||
{
|
||||
// 使用锁对象 m_lockForAbort 来防止并发访问,确保线程安全
|
||||
lock (this.m_lockForAbort)
|
||||
{
|
||||
if (this.m_tryRemoveAction(this.Id, out _)&& this.m_online)
|
||||
// 尝试从管理器中移除当前操作,如果成功且当前状态为在线,则进行中止操作
|
||||
if (this.m_tryRemoveAction(this.Id, out _) && this.m_online)
|
||||
{
|
||||
// 设置在线状态为 false,表示当前操作已离线
|
||||
this.m_online = false;
|
||||
|
||||
// 安全地释放管道流资源,避免资源泄露
|
||||
this.m_pipeStream.SafeDispose();
|
||||
|
||||
// 安全地释放保护数据处理适配器资源,避免资源泄露
|
||||
this.ProtectedDataHandlingAdapter.SafeDispose();
|
||||
|
||||
// 启动一个新的任务来处理管道关闭后的操作,传递中止操作的参数
|
||||
Task.Factory.StartNew(this.PrivateOnNamedPipeClosed, new ClosedEventArgs(manual, msg));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user