Skip to content

Commit f5ae441

Browse files
committed
Merge branch 'main' into HEAD
2 parents 0928451 + c0879a1 commit f5ae441

1 file changed

Lines changed: 59 additions & 40 deletions

File tree

Cyaim.WebSocketServer/Cyaim.WebSocketServer/Infrastructure/Handlers/MvcHandler/MvcChannelHandler.cs

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,18 @@ await bandwidthLimitManager.WaitForBandwidthAsync(
592592
{
593593
await forwardTask;
594594
}
595+
else
596+
{
597+
// 无论是否串行,都处理 Task 异常(关键)
598+
forwardTask = forwardTask.ContinueWith(t =>
599+
{
600+
if (t.IsFaulted)
601+
{
602+
// 记录异常日志,避免未观察到的异常
603+
logger.LogInformation(t.Exception, t.Exception.Message, Encoding.UTF8.GetString(wsReceiveReader.GetBuffer()));
604+
}
605+
}, TaskContinuationOptions.OnlyOnFaulted);
606+
}
595607

596608
// 执行管道 AfterForwardingData
597609
_ = await InvokePipeline(RequestPipelineStage.AfterForwardingData, PipelineContext.CreateForward(context, webSocket, result, wsReceiveReader.GetBuffer(), requestScheme, requestBody, webSocketOption));
@@ -839,7 +851,7 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
839851
{
840852
long requestTime = DateTime.Now.Ticks;
841853
string requestPath = request.Target.ToLower();
842-
854+
IServiceScope serviceScope = null;
843855
try
844856
{
845857
// 从键值对中获取对应的执行函数
@@ -849,20 +861,20 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
849861
{
850862
goto NotFound;
851863
}
852-
Type clss = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class;
853-
if (clss == null)
864+
Type targetClass = webSocketOptions.WatchAssemblyContext.WatchEndPoint.FirstOrDefault(x => x.MethodPath == requestPath)?.Class;
865+
if (targetClass == null)
854866
{
855867
//找不到访问目标
856868
goto NotFound;
857869
}
858870

859871
#region 注入Socket的HttpContext和WebSocket客户端
860-
webSocketOptions.WatchAssemblyContext.MaxConstructorParameters.TryGetValue(clss, out ConstructorParameter constructorParameter);
872+
webSocketOptions.WatchAssemblyContext.MaxConstructorParameters.TryGetValue(targetClass, out ConstructorParameter constructorParameter);
861873

862874
object[] instanceParmas = new object[constructorParameter.ParameterInfos.Length];
863875
// 从Scope DI容器提取目标类构造函数所需的对象
864876
var serviceScopeFactory = WebSocketRouteOption.ApplicationServices.GetService<IServiceScopeFactory>();
865-
var serviceScope = serviceScopeFactory.CreateScope();
877+
serviceScope = serviceScopeFactory.CreateScope();
866878
var scopeIocProvider = serviceScope.ServiceProvider;
867879
for (int i = 0; i < constructorParameter.ParameterInfos.Length; i++)
868880
{
@@ -885,11 +897,11 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
885897
}
886898
}
887899

888-
object inst = Activator.CreateInstance(clss, instanceParmas);
900+
object inst = Activator.CreateInstance(targetClass, instanceParmas);
889901

890902
// 使用注入器工厂注入 HttpContext 和 WebSocket(支持源代码生成和反射两种方式)
891903
var injectorFactory = webSocketOptions.InjectorFactory ?? new EndpointInjectorFactory(webSocketOptions);
892-
var injector = injectorFactory.GetOrCreateInjector(clss);
904+
var injector = injectorFactory.GetOrCreateInjector(targetClass);
893905
injector.Inject(inst, context, webSocket);
894906
#endregion
895907

@@ -1064,51 +1076,55 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
10641076
// Async api support
10651077
if (invokeResult is Task task)
10661078
{
1067-
// 检查是否是 Task<T> 类型
10681079
var taskType = task.GetType();
1069-
if (taskType.IsGenericType && taskType.GetGenericTypeDefinition() == typeof(Task<>))
1070-
{
1071-
// 这是 Task<T>,需要获取返回值
1072-
// 先 await 任务完成,避免同步阻塞
1073-
await task.ConfigureAwait(false);
1080+
bool isGenericTask = taskType.IsGenericType && taskType.GetGenericTypeDefinition() == typeof(Task<>);
10741081

1075-
// 检查任务是否有异常
1076-
if (task.IsFaulted && task.Exception != null)
1077-
{
1078-
// 抛出内部异常(AggregateException 的第一个内部异常)
1079-
var innerException = task.Exception.InnerException ?? task.Exception;
1080-
throw innerException;
1081-
}
1082+
// 预先准备好反射所需的 PropertyInfo(如果是 Task<T>)
1083+
PropertyInfo resultProperty = null;
1084+
if (isGenericTask) resultProperty = taskType.GetProperty("Result");
10821085

1083-
// 使用反射获取 Result 属性值(此时任务已完成,不会阻塞)
1084-
var resultProperty = taskType.GetProperty("Result");
1085-
if (resultProperty != null)
1086+
try
1087+
{
1088+
// 等待任务完成(异步操作,不阻塞线程)
1089+
await task.ConfigureAwait(false);
1090+
}
1091+
catch (Exception ex)
1092+
{
1093+
// await 会抛出 AggregateException,提取内部异常
1094+
if (ex is AggregateException aggEx && aggEx.InnerException != null)
10861095
{
1087-
invokeResult = resultProperty.GetValue(task);
1096+
ex = aggEx.InnerException;
10881097
}
1098+
mvcResponse = await webSocketOptions.OnException(ex, request, mvcResponse, context, webSocketOptions, context.Request.Path, logger).ConfigureAwait(false);
10891099
}
1090-
else
1100+
1101+
// 检查任务状态(await 后任务已完成,但需要检查是否有异常或取消)
1102+
if (task.IsFaulted && task.Exception != null)
10911103
{
1092-
// 这是 Task(无返回值),直接 await
1093-
await task.ConfigureAwait(false);
1104+
// 抛出内部异常(AggregateException 的第一个内部异常)
1105+
var innerException = task.Exception.InnerException ?? task.Exception;
1106+
mvcResponse = await webSocketOptions.OnException(innerException, request, mvcResponse, context, webSocketOptions, context.Request.Path, logger).ConfigureAwait(false);
1107+
}
10941108

1095-
// 检查任务是否有异常
1096-
if (task.IsFaulted && task.Exception != null)
1097-
{
1098-
// 抛出内部异常(AggregateException 的第一个内部异常)
1099-
var innerException = task.Exception.InnerException ?? task.Exception;
1100-
throw innerException;
1101-
}
1109+
if (task.IsCanceled)
1110+
{
1111+
mvcResponse = await webSocketOptions.OnException(new TaskCanceledException(task), request, mvcResponse, context, webSocketOptions, context.Request.Path, logger).ConfigureAwait(false);
1112+
}
11021113

1114+
// 检查是否是 Task<T> 类型,需要获取返回值
1115+
if (isGenericTask && resultProperty != null)
1116+
{
1117+
// 使用预先准备好的 PropertyInfo 获取结果(此时任务已完成,不会阻塞)
1118+
invokeResult = resultProperty.GetValue(task);
1119+
}
1120+
else
1121+
{
11031122
invokeResult = null;
11041123
}
11051124
}
11061125

11071126
#endregion
11081127

1109-
// Dispose ioc scope
1110-
serviceScope?.Dispose();
1111-
serviceScope = null;
11121128

11131129
mvcResponse.Id = request.Id;
11141130
mvcResponse.Target = request.Target;
@@ -1127,11 +1143,14 @@ public static async Task<MvcResponseScheme> MvcDistributeAsync(WebSocketRouteOpt
11271143

11281144
MvcResponseScheme customResp = await webSocketOptions.OnException(ex, request, resp, context, webSocketOptions, context.Request.Path, logger).ConfigureAwait(false);
11291145

1130-
//if (!webSocketOptions.IsDevelopment)
1131-
// resp.Msg = null;
1132-
11331146
return customResp;
11341147
}
1148+
finally
1149+
{
1150+
// Dispose ioc scope
1151+
serviceScope?.Dispose();
1152+
serviceScope = null;
1153+
}
11351154

11361155
NotFound:
11371156
logger.LogInformation(string.Format(I18nText.WS_INTERACTIVE_TEXT_TEMPALTE, context.Connection.RemoteIpAddress, context.Connection.RemotePort, context.Connection.Id, I18nText.MvcDistributeAsync_EndPointNotFound + requestPath));

0 commit comments

Comments
 (0)