使用C#调用Azure DevOps REST API提交文件至分支遇Method Not Allowed错误
问题描述
调用PostAsync提交数据时收到Method Not Allowed错误,响应体提示:
The requested resource does not support http method 'POST'
需求是实现等效于创建本地分支、添加带内容的文件、git add、commit、push的操作,部署在本地服务器,查阅文档后认为接口应该支持POST请求。
提交代码:
public async Task<CreateCommitResponse> CreateCommitFileCommitAsync(string repositoryName, string branch, string fileContent, string comment, string fileName) { var pat = m_serverPats[m_adoSspServer]; // Retrieve repository info var repositoryInfos = await GetRepositoryByNameAsync(repositoryName); if (repositoryInfos == null) { Tools.LogError($"Could not get repository 'm_adoSspRepo' infos"); return new CreateCommitResponse() { Created=false,ErrorMessage= $"Could not get repository 'm_adoSspRepo' infos" }; } string endpoint = $"https://{m_adoSspServer}/{m_adoSspProject}/_apis/git/repositories/{repositoryInfos.Id}/pushes?api-version=7.1-preview.1"; // Fetch the latest commit ID for the target branch var latestCommitId = await GetLatestCommitIdAsync(repositoryInfos.Id, branch); if (latestCommitId == null) { Tools.LogError($"Could not fetch the latest commit for branch '{branch}'"); return new CreateCommitResponse() { Created = false, ErrorMessage = $"Could not fetch the latest commit for branch '{branch}'" }; } // Create the first commit (e.g., adding a README.md file) var commitData = new { commits = new[] { new { comment = comment, changes = new[] { new { changeType = "add", item = new { path = $"/{fileName}" }, newContent = new { content = fileContent, contentType = "rawText" } } } } }, refUpdates = new[] { new { name = $"refs/heads/{branch}", // Creating the main branch oldObjectId = latestCommitId } } }; // Serialize the commit payload string jsonContent = JsonConvert.SerializeObject(commitData); using (var client = new HttpClient()) { // Set up HTTP client client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($":{pat}"))); // Make the POST request to create the first commit and the main branch var response = await client.PostAsync(endpoint, new StringContent(jsonContent, Encoding.UTF8, "application/json")); if (response.StatusCode != System.Net.HttpStatusCode.OK) { Tools.LogError($"Failed to create commit and branch: {response.StatusCode} - {response.ReasonPhrase}"); return new CreateCommitResponse() { Created = false, ErrorMessage = $"Failed to create commit and branch: {response.StatusCode} - {response.ReasonPhrase}" }; } } return new CreateCommitResponse() { Created = true, ErrorMessage = null }; }
获取分支最新Commit ID的代码:
private async Task<string?> GetLatestCommitIdAsync(string repositoryId, string branchName) { string endpoint = $"https://{m_adoSspServer}/{m_adoSspProject}/_apis/git/repositories/{repositoryId}/commits?searchCriteria.itemVersion.version={branchName}&$top=1&api-version=7.1-preview.1"; using (var client = new HttpClient()) { // Set up HTTP client with authorization headers client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($":{m_serverPats[m_adoSspServer]}"))); // Make the GET request to retrieve the latest commit ID var response = await client.GetAsync(endpoint); if (response.StatusCode != System.Net.HttpStatusCode.OK) { Tools.LogError($"Failed to retrieve latest commit ID for branch '{branchName}': {response.StatusCode} - {response.ReasonPhrase}"); return null; } var content = await response.Content.ReadAsStringAsync(); dynamic result = JsonConvert.DeserializeObject(content); JArray valuesArray = (JArray)result["value"]; string commitId = valuesArray[0]["commitId"].ToString(); return commitId; } }
问题分析与解决
1. 分支创建逻辑错误
你的需求是创建新分支,但当前代码中GetLatestCommitIdAsync是去查询目标分支的最新Commit ID——如果这个分支在远程还不存在,这个接口会返回空,导致流程中断。正确的做法是:
- 基于一个已存在的基础分支(比如
main/master)获取最新Commit ID,作为新分支的起点; - 如果是从空仓库创建第一个分支,
oldObjectId应设为全0的SHA值:0000000000000000000000000000000000000000
2. API版本选择问题
你使用的7.1-preview.1是预览版API,可能存在接口行为不稳定或路径变更的情况。建议切换到稳定版API(比如7.0或7.2),Pushes API的POST方法在稳定版中是明确支持的。
3. 错误信息排查不充分
当前代码仅打印了状态码和原因短语,没有读取响应体的详细错误内容。修改错误处理逻辑,添加读取响应体的代码:
if (response.StatusCode != System.Net.HttpStatusCode.OK) { var errorContent = await response.Content.ReadAsStringAsync(); Tools.LogError($"Failed to create commit and branch: {response.StatusCode} - {response.ReasonPhrase}. Details: {errorContent}"); return new CreateCommitResponse() { Created = false, ErrorMessage = $"Failed to create commit and branch: {response.StatusCode} - {response.ReasonPhrase}. Details: {errorContent}" }; }
这能帮你获取更具体的服务器错误提示,精准定位问题根源。
4. 分支不存在时的refUpdates配置
如果是创建全新分支,refUpdates中的oldObjectId需要设置为你要基于的父Commit ID(比如基础分支的最新ID),而不是目标分支的ID(因为目标分支还不存在)。
5. 路径格式问题
检查path = $"/{fileName}"是否符合仓库的路径规范,有些场景下不需要开头的斜杠,需确保路径相对于仓库根目录的正确性。
内容的提问来源于stack exchange,提问作者pf12345678910
相关产品推荐
相关产品推荐

