mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-17 17:06:45 +08:00
发布:4.0.3
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<BaseVersion>4.0.2</BaseVersion>
|
<BaseVersion>4.0.3</BaseVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public class WebSocketDmtpService : ConnectableService<WebSocketDmtpSessionClien
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>异步任务。</returns>
|
/// <returns>异步任务。</returns>
|
||||||
/// <exception cref="NotSupportedException">抛出不支持异常。</exception>
|
/// <exception cref="NotSupportedException">抛出不支持异常。</exception>
|
||||||
public override Task StartAsync()
|
public override Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("此服务的生命周期跟随主Host");
|
throw new NotSupportedException("此服务的生命周期跟随主Host");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,14 +169,22 @@ public abstract class HttpDmtpSessionClient : HttpSessionClient, IHttpDmtpSessio
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override async Task OnTcpClosed(ClosedEventArgs e)
|
protected override async Task OnTcpClosed(ClosedEventArgs e)
|
||||||
{
|
{
|
||||||
await this.OnDmtpClosed(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
if (this.m_dmtpActor!=null)
|
||||||
|
{
|
||||||
|
await this.OnDmtpClosed(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
}
|
||||||
|
|
||||||
await base.OnTcpClosed(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await base.OnTcpClosed(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override async Task OnTcpClosing(ClosingEventArgs e)
|
protected override async Task OnTcpClosing(ClosingEventArgs e)
|
||||||
{
|
{
|
||||||
await this.PluginManager.RaiseAsync(typeof(IDmtpClosingPlugin), this.Resolver, this, e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
if (this.m_dmtpActor != null)
|
||||||
|
{
|
||||||
|
await this.PluginManager.RaiseIDmtpClosingPluginAsync(this.Resolver, this, e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
}
|
||||||
|
|
||||||
await base.OnTcpClosing(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await base.OnTcpClosing(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +195,7 @@ public abstract class HttpDmtpSessionClient : HttpSessionClient, IHttpDmtpSessio
|
|||||||
{
|
{
|
||||||
if (!await this.m_dmtpActor.InputReceivedData(message).ConfigureAwait(EasyTask.ContinueOnCapturedContext))
|
if (!await this.m_dmtpActor.InputReceivedData(message).ConfigureAwait(EasyTask.ContinueOnCapturedContext))
|
||||||
{
|
{
|
||||||
await this.PluginManager.RaiseAsync(typeof(IDmtpReceivedPlugin), this.Resolver, this, new DmtpMessageEventArgs(message)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await this.PluginManager.RaiseIDmtpReceivedPluginAsync(this.Resolver, this, new DmtpMessageEventArgs(message)).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await base.OnTcpReceived(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await base.OnTcpReceived(e).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using TouchSocket.Core.AspNetCore;
|
using TouchSocket.Core.AspNetCore;
|
||||||
using TouchSocket.Hosting;
|
using TouchSocket.Hosting;
|
||||||
using TouchSocket.Hosting.Sockets.HostService;
|
using TouchSocket.Hosting.HostedServices;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection;
|
namespace Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -143,6 +143,20 @@ public static class ServiceCollectionExtensions
|
|||||||
return AddSetupConfigObjectHostedService<ServiceHost<TObjectService>, TObjectService, TObjectImpService>(services, actionConfig);
|
return AddSetupConfigObjectHostedService<ServiceHost<TObjectService>, TObjectService, TObjectImpService>(services, actionConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddClientHostedService<TObjectClient, [DynamicallyAccessedMembers(AOT.Container)] TClientImpService>(this IServiceCollection services, Action<TouchSocketConfig> actionConfig)
|
||||||
|
where TObjectClient : class, ISetupConfigObject, IConnectableClient,IClosableClient
|
||||||
|
where TClientImpService : class, TObjectClient
|
||||||
|
{
|
||||||
|
return AddSetupConfigObjectHostedService<ClientHost<TObjectClient>, TObjectClient, TClientImpService>(services, actionConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddSetupConfigObjectHostedService<TObject, [DynamicallyAccessedMembers(AOT.Container)] TObjectImp>(this IServiceCollection services, Action<TouchSocketConfig> actionConfig)
|
||||||
|
where TObject : class, ISetupConfigObject
|
||||||
|
where TObjectImp : class, TObject
|
||||||
|
{
|
||||||
|
return AddSetupConfigObjectHostedService<SetupConfigObjectHostedService<TObject>, TObject, TObjectImp>(services, actionConfig);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加配置对象托管服务
|
/// 添加配置对象托管服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
50
src/TouchSocket.Hosting/HostedServices/ClientHost.cs
Normal file
50
src/TouchSocket.Hosting/HostedServices/ClientHost.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||||
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||||
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||||
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||||
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||||
|
// Github源代码仓库:https://github.com/RRQM
|
||||||
|
// API首页:https://touchsocket.net/
|
||||||
|
// 交流QQ群:234762506
|
||||||
|
// 感谢您的下载和使用
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using TouchSocket.Resources;
|
||||||
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
|
namespace TouchSocket.Hosting.HostedServices;
|
||||||
|
|
||||||
|
internal class ClientHost<TService> : SetupConfigObjectHostedService<TService> where TService : ISetupConfigObject, IConnectableClient,IClosableClient
|
||||||
|
{
|
||||||
|
private ILogger<TService> m_logger;
|
||||||
|
|
||||||
|
protected override void OnSetResolver(IResolver resolver)
|
||||||
|
{
|
||||||
|
base.OnSetResolver(resolver);
|
||||||
|
this.m_logger = resolver.GetService<ILogger<TService>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await base.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
await this.ConfigObject.ConnectAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
|
||||||
|
this.m_logger.LogInformation("{Message}", TouchSocketHostingResource.HostServerStarted);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.m_logger.LogError(ex, "{Message}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await this.ConfigObject.CloseAsync("服务停止",cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
await base.StopAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using TouchSocket.Resources;
|
using TouchSocket.Resources;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
namespace TouchSocket.Hosting.Sockets.HostService;
|
namespace TouchSocket.Hosting.HostedServices;
|
||||||
|
|
||||||
internal class ServiceHost<TService> : SetupConfigObjectHostedService<TService> where TService : ISetupConfigObject, IServiceBase
|
internal class ServiceHost<TService> : SetupConfigObjectHostedService<TService> where TService : ISetupConfigObject, IServiceBase
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ internal class ServiceHost<TService> : SetupConfigObjectHostedService<TService>
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await base.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await base.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
await this.ConfigObject.StartAsync().ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await this.ConfigObject.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
|
||||||
this.m_logger.LogInformation("{Message}", TouchSocketHostingResource.HostServerStarted);
|
this.m_logger.LogInformation("{Message}", TouchSocketHostingResource.HostServerStarted);
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ internal class ServiceHost<TService> : SetupConfigObjectHostedService<TService>
|
|||||||
|
|
||||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await this.ConfigObject.StopAsync();
|
await this.ConfigObject.StopAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
|
await base.StopAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Hosting;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// SetupObjectHostedService
|
/// SetupObjectHostedService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SetupConfigObjectHostedService<TConfigObject> : IHostedService where TConfigObject : ISetupConfigObject
|
public class SetupConfigObjectHostedService<TConfigObject> : IHostedService where TConfigObject : ISetupConfigObject
|
||||||
{
|
{
|
||||||
private TouchSocketConfig m_config;
|
private TouchSocketConfig m_config;
|
||||||
private TConfigObject m_configObject;
|
private TConfigObject m_configObject;
|
||||||
@@ -81,5 +81,9 @@ public abstract class SetupConfigObjectHostedService<TConfigObject> : IHostedSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract Task StopAsync(CancellationToken cancellationToken);
|
public virtual Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.m_configObject.Dispose();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||||
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||||
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||||
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||||
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||||
|
// Github源代码仓库:https://github.com/RRQM
|
||||||
|
// API首页:https://touchsocket.net/
|
||||||
|
// 交流QQ群:234762506
|
||||||
|
// 感谢您的下载和使用
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
|
namespace TouchSocket.Http.WebSockets;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提供用于为 <see cref="ReconnectionOption{TClient}"/> 配置 WebSocket 心跳检查的扩展方法。
|
||||||
|
/// </summary>
|
||||||
|
public static class ReconnectionOptionsExtension
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为 <see cref="ReconnectionOption{TClient}"/> 设置一个基于活动时间与 Ping 的检查动作。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TClient">实现了 <see cref="IConnectableClient"/>, <see cref="IOnlineClient"/>, <see cref="IDependencyClient"/>, <see cref="IWebSocketClient"/> 的客户端类型。</typeparam>
|
||||||
|
/// <param name="reconnectionOption">要配置的 <see cref="ReconnectionOption{TClient}"/> 实例。</param>
|
||||||
|
/// <param name="activeTimeSpan">在此时间范围内若有活动则跳过心跳检测,默认 3 秒。</param>
|
||||||
|
/// <param name="pingTimeout">执行 Ping 与 Close 操作时的超时时间,默认 5 秒。</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="activeTimeSpan"/> 或 <paramref name="pingTimeout"/> 小于或等于零时抛出。</exception>
|
||||||
|
public static void UseWebSocketCheckAction<TClient>(
|
||||||
|
this ReconnectionOption<TClient> reconnectionOption,
|
||||||
|
TimeSpan? activeTimeSpan = null,
|
||||||
|
TimeSpan? pingTimeout = null)
|
||||||
|
where TClient : IConnectableClient, IOnlineClient, IDependencyClient, IWebSocketClient
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowIfNull(reconnectionOption, nameof(reconnectionOption));
|
||||||
|
var span = activeTimeSpan ?? TimeSpan.FromSeconds(3);
|
||||||
|
var timeout = pingTimeout ?? TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
|
// 验证时间参数的有效性
|
||||||
|
if (span <= TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(activeTimeSpan), "活动时间间隔必须大于零");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout <= TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(pingTimeout), "Ping超时时间必须大于零");
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectionOption.CheckAction = async (client) =>
|
||||||
|
{
|
||||||
|
// 第1步:快速在线状态检查
|
||||||
|
// 如果客户端已经离线,无需进一步检查,直接返回Dead状态
|
||||||
|
if (!client.Online)
|
||||||
|
{
|
||||||
|
return ConnectionCheckResult.Dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步:活动时间检查
|
||||||
|
// 如果客户端在指定时间内有活动,说明连接正常,跳过本次心跳检查
|
||||||
|
var lastActiveTime = client.GetLastActiveTime();
|
||||||
|
var timeSinceLastActivity = DateTimeOffset.UtcNow - lastActiveTime;
|
||||||
|
|
||||||
|
if (timeSinceLastActivity < span)
|
||||||
|
{
|
||||||
|
return ConnectionCheckResult.Skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第3步:主动心跳检查
|
||||||
|
// 通过Ping操作验证连接的实际可用性
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var pingCts = new CancellationTokenSource(timeout);
|
||||||
|
var pingResult = await client.PingAsync(pingCts.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (pingResult.IsSuccess)
|
||||||
|
{
|
||||||
|
return ConnectionCheckResult.Alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var closeCts = new CancellationTokenSource(timeout);
|
||||||
|
|
||||||
|
var closeResult = await client.CloseAsync("心跳插件ping失败主动断开连接", closeCts.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return ConnectionCheckResult.Dead;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Ping超时,认为连接已死
|
||||||
|
return ConnectionCheckResult.Dead;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 其他异常也认为连接不可用
|
||||||
|
return ConnectionCheckResult.Dead;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,7 +119,7 @@ public abstract class NamedPipeServiceBase<TClient> : ConnectableService<TClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task StartAsync()
|
public override async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
this.ThrowIfConfigIsNull();
|
this.ThrowIfConfigIsNull();
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public abstract class ServiceBase : SetupConfigObject, IServiceBase
|
|||||||
public abstract ServerState ServerState { get; }
|
public abstract ServerState ServerState { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract Task StartAsync();
|
public abstract Task StartAsync(CancellationToken cancellationToken=default);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract Task<Result> StopAsync(CancellationToken cancellationToken = default);
|
public abstract Task<Result> StopAsync(CancellationToken cancellationToken = default);
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public abstract class TcpServiceBase<TClient> : ConnectableService<TClient>, ITc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task StartAsync()
|
public override async Task StartAsync(CancellationToken cancellationToken=default)
|
||||||
{
|
{
|
||||||
this.ThrowIfDisposed();
|
this.ThrowIfDisposed();
|
||||||
this.ThrowIfConfigIsNull();
|
this.ThrowIfConfigIsNull();
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ public abstract class UdpSessionBase : ServiceBase, IUdpSessionBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task StartAsync()
|
public override async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
this.ThrowIfDisposed();
|
this.ThrowIfDisposed();
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public static class ServiceExtension
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IServiceBase.StartAsync"/>
|
/// <inheritdoc cref="IServiceBase.StartAsync"/>
|
||||||
public static async Task StartAsync<TService>(this TService service, IPHost iPHost) where TService : IUdpSession
|
public static async Task StartAsync<TService>(this TService service, IPHost iPHost, CancellationToken cancellationToken = default) where TService : IUdpSession
|
||||||
{
|
{
|
||||||
TouchSocketConfig config;
|
TouchSocketConfig config;
|
||||||
if (service.Config == null)
|
if (service.Config == null)
|
||||||
@@ -101,7 +101,7 @@ public static class ServiceExtension
|
|||||||
config = service.Config;
|
config = service.Config;
|
||||||
config.SetBindIPHost(iPHost);
|
config.SetBindIPHost(iPHost);
|
||||||
}
|
}
|
||||||
await service.StartAsync().ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await service.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Udp
|
#endregion Udp
|
||||||
|
|||||||
@@ -184,11 +184,11 @@ public static class TouchSocketConfigExtension
|
|||||||
/// <typeparam name="TClient"></typeparam>
|
/// <typeparam name="TClient"></typeparam>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<TClient> BuildClientAsync<TClient>(this TouchSocketConfig config) where TClient : ISetupConfigObject, IConnectableClient, new()
|
public static async Task<TClient> BuildClientAsync<TClient>(this TouchSocketConfig config, CancellationToken cancellationToken = default) where TClient : ISetupConfigObject, IConnectableClient, new()
|
||||||
{
|
{
|
||||||
var client = new TClient();
|
var client = new TClient();
|
||||||
await client.SetupAsync(config).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await client.SetupAsync(config).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
await client.ConnectAsync().ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await client.ConnectAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,11 +198,11 @@ public static class TouchSocketConfigExtension
|
|||||||
/// <typeparam name="TService"></typeparam>
|
/// <typeparam name="TService"></typeparam>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<TService> BuildServiceAsync<TService>(this TouchSocketConfig config) where TService : IServiceBase, new()
|
public static async Task<TService> BuildServiceAsync<TService>(this TouchSocketConfig config, CancellationToken cancellationToken = default) where TService : IServiceBase, new()
|
||||||
{
|
{
|
||||||
var service = new TService();
|
var service = new TService();
|
||||||
await service.SetupAsync(config).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await service.SetupAsync(config).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
await service.StartAsync().ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
await service.StartAsync(cancellationToken).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
#endregion 创建
|
#endregion 创建
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public interface IServiceBase : ISetupConfigObject
|
|||||||
/// 异步启动
|
/// 异步启动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="Exception">可能启动时遇到的异常</exception>
|
/// <exception cref="Exception">可能启动时遇到的异常</exception>
|
||||||
Task StartAsync();
|
Task StartAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步停止服务器
|
/// 异步停止服务器
|
||||||
|
|||||||
Reference in New Issue
Block a user