在C# Azure Function中使用EF Core捕获读取错误的最佳实践
问题描述
我编写了如下函数:
public async Task<List<DTO.Currency_DTO>> GetCurrencyAsync() { try { return await _ripple_primary_context.RipplCurrencies.Select(p => new DTO.Currency_DTO { currency_id = p.CurrencyId, currency_name = p.CurrencyName, currency_alpha_code = p.CurrencyAlphaCode }).ToListAsync(); } catch (Exception ex) { } }
该函数返回自定义DTO(仅包含特定字段)。我有以下疑问:
- 捕获读取错误的最佳方式是什么?即catch块内应编写什么逻辑?
- 是否存在专门针对读取错误的异常类型?我目前仅找到针对写入错误的异常。
- 发生错误时最佳的返回内容是什么?我猜测仍需保持DTO模型的结构。
解决方案
一、Catch块的最佳逻辑
- 记录异常信息:必须把异常的类型、消息、堆栈追踪记录到日志系统(如NLog、Serilog),这是排查问题的核心依据,绝对不能留空catch块。
- 决定是否重新抛出异常:
- 如果当前方法无法处理错误(比如数据库连接失败、权限不足),用
throw;重新抛出异常(保留原始堆栈信息,不要用throw ex;破坏堆栈),让上层调用者处理(比如给前端返回500错误)。 - 若需要封装业务异常,可自定义异常类并传递原始异常,例如:
throw new DataReadException("读取货币数据失败", ex);
- 如果当前方法无法处理错误(比如数据库连接失败、权限不足),用
- 禁止静默失败:空catch会导致错误完全被隐藏,调用者无法感知问题,这是严重的开发陋习。
二、针对读取的专门异常类型
EF Core或ADO.NET中没有内置的“读取异常”类型,数据库操作的异常基本都属于DbException及其子类(比如SqlServer的SqlException、MySQL的MySqlException)。
你可以通过两种方式区分读取相关错误:
- 通过错误码判断:不同数据库的错误码有对应场景,比如SqlServer中10054代表连接中断(读取时可能触发),2627代表主键冲突(写入时触发),可根据错误码分类处理。
- 自定义业务异常:自己定义
DataReadFailedException这类异常,在catch到DbException后,结合当前是读取操作的上下文,抛出这个自定义异常,让上层更清晰识别错误类型。
三、错误时的返回内容
需结合业务场景选择:
- 返回空列表:仅适用于业务允许“无数据”和“读取错误”等价处理的场景(比如前端只展示列表,错误时显示空列表),但会隐藏错误,不推荐用于需要明确错误反馈的场景。
- 抛出异常:这是更合理的方式,读取失败属于异常情况,不应以正常返回值掩盖错误。上层调用者可捕获异常,返回对应错误信息(比如给前端返回500状态码+提示文本)。
- 返回带状态的包装类:如果需要统一接口返回格式,可定义通用结果类:
public class ApiResult<T> { public bool Success { get; set; } public T Data { get; set; } public string ErrorMessage { get; set; } }
此时方法返回类型改为Task<ApiResult<List<DTO.Currency_DTO>>>, 错误时返回:
return new ApiResult<List<DTO.Currency_DTO>> { Success = false, Data = null, ErrorMessage = "读取货币数据失败,请稍后重试" };
这种方式能明确告知调用者操作结果,同时保留错误信息,适合API接口场景。
内容的提问来源于stack exchange,提问作者Jason_Hough
相关产品推荐
相关产品推荐

