C#中如何处理await Task返回null引发的异常?
问题分析与解决方案
根本原因
你遇到的StatusCode="Cancelled"异常,并非await处理null导致,而是gRPC Blazor WebView的协议限制:gRPC服务方法返回null时,会被判定为"未返回有效消息",进而触发取消状态的异常。
可行解决方案
方案1:用自定义结果对象包装返回值
创建包含状态标记的结果类,明确区分"找到数据"和"未找到数据"的场景,避免直接返回null:
// 定义结果包装类 public class DatabaseRegistryResult { public bool IsFound { get; set; } public DatabaseRegistry? Registry { get; set; } } // 修改GetByName方法 public async Task<DatabaseRegistryResult> GetByName(string datasetName) { try { var entities = await _repository.GetAllAsync(); var matchedRegistry = entities.FirstOrDefault(e => e.Name == datasetName); return new DatabaseRegistryResult { IsFound = matchedRegistry != null, Registry = matchedRegistry }; } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); throw new RpcException(new Status(StatusCode.Internal, "An error occurred while retrieving the database.")); } } // 调用方逻辑 var queryResult = await appEngine.DatabaseRegistryService.GetByName(result.FileName); if (queryResult.IsFound) { // 处理找到数据的逻辑 var curDbService = queryResult.Registry; } else { // 处理未找到数据的逻辑 }
方案2:用Nullable引用类型(C# 8+)
如果项目已启用Nullable引用类型(在csproj中设置<Nullable>enable</Nullable>),可直接返回可空的DatabaseRegistry?,同时确保gRPC服务配置允许返回可空类型:
// 修改GetByName方法 public async Task<DatabaseRegistry?> GetByName(string datasetName) { try { var entities = await _repository.GetAllAsync(); // 直接返回FirstOrDefault结果,无需额外包装Task.FromResult return entities.FirstOrDefault(e => e.Name == datasetName); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); throw new RpcException(new Status(StatusCode.Internal, "An error occurred while retrieving the database.")); } } // 调用方逻辑保持不变 var curDbService = await appEngine.DatabaseRegistryService.GetByName(result.FileName); if (curDbService != null) { // 处理找到数据的逻辑 } else { // 处理未找到数据的逻辑 }
方案3:用异常区分"未找到"场景
如果业务允许将"未找到"视为异常场景,可抛出NotFound状态的gRPC异常,在调用方捕获后处理:
// 修改GetByName方法 public async Task<DatabaseRegistry> GetByName(string datasetName) { try { var entities = await _repository.GetAllAsync(); var matchedRegistry = entities.FirstOrDefault(e => e.Name == datasetName); if (matchedRegistry == null) { throw new RpcException(new Status(StatusCode.NotFound, $"Registry '{datasetName}' not found.")); } return matchedRegistry; } catch (RpcException) { // 重新抛出gRPC异常,不做额外包裹 throw; } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); throw new RpcException(new Status(StatusCode.Internal, "An error occurred while retrieving the database.")); } } // 调用方逻辑 try { var curDbService = await appEngine.DatabaseRegistryService.GetByName(result.FileName); // 处理找到数据的逻辑 } catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) { // 处理未找到数据的逻辑 } catch (RpcException ex) when (ex.StatusCode == StatusCode.Internal) { // 处理内部错误逻辑 }
内容的提问来源于stack exchange,提问作者Penny
相关产品推荐
相关产品推荐

