如何用Octokit实现文件存在则更新、不存在则创建(避免try-catch)
问题:使用Octokit实现文件不存在则创建、存在则更新的简洁方式?
我想了解是否有一种简洁的方式,使用Octokit库实现指定文件不存在时创建新文件,存在则更新它?目前我通过try-catch块来实现,但希望找到除try-catch之外更直接的方法。
以下是我的代码实现:
private IRepositoryContentsClient Content => _client.Repository.Content; public void TransmitLog(string logFilePath) { var logContent = LogFileToString(logFilePath); var githubPath = GenerateGithubPath(logFilePath); try { UpdateLog(githubPath, logContent); } catch (NotFoundException) { CreateLog(githubPath, logContent); } catch (AggregateException) { CreateLog(githubPath, logContent); } } private void UpdateLog(string githubPath, string logContent) { // MY APP FAILS HERE var existingFile = Content.GetAllContentsByRef( _owner, _repo, githubPath, _branch).Result; // update the file var relevantSha = existingFile.First().Sha; var updateRequest = new UpdateFileRequest("Log update" + DateTime.UtcNow, logContent, relevantSha, _branch); var updateChangeSet = Content.UpdateFile(_owner, _repo, githubPath, updateRequest); } private void CreateLog(string githubPath, string logFileContent) { // if file is not found, create it var createRequest = new CreateFileRequest("Log Creation" + DateTime.UtcNow, logFileContent, _branch); var createChangeSet = Content.CreateFile(_owner, _repo, githubPath, createRequest); }
编辑说明:最初我将CreateLog和UpdateLog都声明为async void,这引发了一系列其他问题,现已修正,我现在真正关注的是如何避免这种try-catch结构。
解决方案
Octokit本身并没有提供直接的"upsert(存在则更新,不存在则创建)"接口,因为GitHub的REST API也没有单一的端点支持这个操作。不过我们可以优化逻辑,将"先尝试更新再捕获异常"的模式,改为主动检查文件存在性,让代码逻辑更清晰,减少不必要的API调用。
优化后的代码实现
private IRepositoryContentsClient Content => _client.Repository.Content; // 改为async Task避免同步调用.Result带来的死锁问题 public async Task TransmitLog(string logFilePath) { var logContent = LogFileToString(logFilePath); var githubPath = GenerateGithubPath(logFilePath); IReadOnlyList<RepositoryContent> existingFile = null; try { // 主动检查文件是否存在 existingFile = await Content.GetAllContentsByRef(_owner, _repo, githubPath, _branch); } catch (NotFoundException) { // 文件不存在,直接创建 await CreateLog(githubPath, logContent); return; } catch (AggregateException ae) when (ae.InnerException is NotFoundException) { // 处理异步调用包装的NotFoundException await CreateLog(githubPath, logContent); return; } // 文件存在,执行更新(直接复用已获取的SHA,无需再次调用API) await UpdateLog(githubPath, logContent, existingFile.First().Sha); } // 直接传入已获取的SHA,避免重复查询文件信息 private async Task UpdateLog(string githubPath, string logContent, string fileSha) { var updateRequest = new UpdateFileRequest($"Log update {DateTime.UtcNow}", logContent, fileSha, _branch); await Content.UpdateFile(_owner, _repo, githubPath, updateRequest); } private async Task CreateLog(string githubPath, string logFileContent) { var createRequest = new CreateFileRequest($"Log Creation {DateTime.UtcNow}", logFileContent, _branch); await Content.CreateFile(_owner, _repo, githubPath, createRequest); }
优化点说明
- 主动检查存在性:先调用
GetAllContentsByRef判断文件是否存在,而不是先尝试更新再捕获异常,逻辑更直观。 - 减少API调用:获取文件信息后直接复用其SHA值,避免在
UpdateLog中重复查询文件内容。 - 异步优化:将方法改为
async Task,避免使用.Result带来的潜在死锁问题,符合异步编程最佳实践。 - 精准异常过滤:使用
when关键字过滤AggregateException,只处理内部为NotFoundException的情况,避免捕获无关异常。
如果想要完全避免try-catch,目前没有可行方案——因为GitHub API在文件不存在时必然会返回404,Octokit会将其包装为NotFoundException抛出,这是无法绕过的。但上述优化后的代码已经将异常处理从"控制流工具"转化为"错误处理手段",代码结构更清晰易读。
内容的提问来源于stack exchange,提问作者emilaz
相关产品推荐
相关产品推荐

