为何Prise插件中TaskCanceledException无法捕获,其他异常却可以?
Prise插件框架中TaskCanceledException无法被上层捕获的问题与解决办法
问题背景
我在使用Prise Plugin Framework和MailKit SMTP Client时遇到异常处理异常:当调用ConnectAsync异步超时抛出TaskCanceledException时,该异常在调用方被捕获并记录日志后重新抛出,但无法被Prise插件Execute方法的上层catch块捕获,直接导致应用崩溃;而其他类型的异常则能正常被上层捕获,不会引发崩溃。
相关代码示例
初始异常捕获逻辑
try { await _smtpClient.ConnectAsync(sendEmail.Host, sendEmail.Port); // 其他业务代码 } catch { // 日志记录逻辑 throw; }
这段代码由插件通过return await service.ExecuteAsync(parameters, context);调用,原本预期异常会抛到父级处理,但未生效。
插件类及上层调用代码
[Plugin(PluginType = typeof(IPlugin))] [PluginDescription(Description = "Email plugin.")] public class Email : BasePlugin<EmailInputModel> { [field: PluginService(ProvidedBy = ProvidedBy.Host, ServiceType = typeof(IServiceProvider))] private IServiceProvider ServiceProvider { get; set; } [PluginActivated] public void OnActivated() { InitializeServices(ServiceProvider); } protected override async Task<PluginExecutionResult> ExecutePluginAsync( EmailInputModel parameters, PluginExecutionContext context, IServiceProvider provider) { IEmailPluginService service = provider.GetRequiredService<IEmailPluginService>(); return await service.ExecuteAsync(parameters, context); } } // 调用插件Execute方法的上层逻辑 public async Task<PluginExecutionResult> ExecuteAsync(string parameters, PluginExecutionContext context) { try { var pluginParameters = JsonConvert.DeserializeObject<TInput>(parameters); using var scope = _serviceProvider.CreateScope(); return await ExecutePluginAsync(pluginParameters, context, scope.ServiceProvider); } catch (Exception exception) { // 预期在此捕获异常,但实际未触发 throw; } }
解决办法
我通过在Connect超时后专门捕获OperationCanceledException(TaskCanceledException是它的子类),并在catch块中抛出一个自定义异常,解决了这个问题。调整后的核心代码如下:
try { await _smtpClient.ConnectAsync(sendEmail.Host, sendEmail.Port); // 其他业务代码 } catch (OperationCanceledException) { // 日志记录 throw new CustomEmailTimeoutException("SMTP连接超时"); // 自定义异常类,需提前定义 } catch { // 其他异常处理及日志 throw; }
内容的提问来源于stack exchange,提问作者DanS
相关产品推荐
相关产品推荐

