使用C#通过Azure DevOps API上传工作项附件不显示文件名问题
问题:Azure DevOps工作项附件不显示文件名,下载时变为附件ID
我使用C#结合Azure DevOps REST API编写代码,将文件附加到已创建的工作项中。目前附件已成功关联到工作项,下载后数据正常,但附件不显示文件名,下载时文件名变为附件ID。相关代码如下:
private void UploadAttachmentAsync(int workItemId, string destinationResultsLocation, string fitnesseDataTableName) { string fi = System.IO.Directory.GetFiles(destinationResultsLocation).FirstOrDefault(); var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fi)); fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); // Extract just the file name var fileName = Path.GetFileName(fi); fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = fileName, Name = "file" }; // Upload the file to Azure DevOps string requestUrl = $"{OrganizationUrl}{ProjectName}/_apis/wit/attachments?api-version=7.0"; HttpResponseMessage response = client.PostAsync(requestUrl, fileContent).Result; if (response.IsSuccessStatusCode) { var jsonResponse = response.Content.ReadAsStringAsync().Result; // Extract attachment URL from the response var jsonObject = JObject.Parse(jsonResponse); // Extract the URL from the response, which contains the attachment URL var attachmentUrl = jsonObject["url"].ToString(); // Now, link the attachment to the work item LinkAttachmentToWorkItemAsync(workItemId, attachmentUrl, fileName); } else { Console.WriteLine("Error uploading attachment: " + response.StatusCode); } } private void LinkAttachmentToWorkItemAsync(int workItemId, string attachmenturl, string fileName) { var jsonContent = new List<JsonPatchOperation> { new JsonPatchOperation { op = "add", path = "/relations/-", // Add a new relation (attachment) value = new Relation { rel = "AttachedFile", // Define the type of relation (attachment) url = attachmenturl, // URL where the attachment is stored displayName = fileName, // Display name of the attachment attributes = new attributes { comment = $"Uploaded attachment: {fileName}" // Optional comment or description } } } }; var content = new StringContent(_serializer.Serialize(jsonContent), Encoding.UTF8, "application/json-patch+json"); var response = client.PatchAsync($"{OrganizationUrl}{ProjectName}/_apis/wit/workitems/{workItemId}?api-version=7.1", content).Result; if (response.IsSuccessStatusCode) { Console.WriteLine("Attachment linked to work item successfully."); } else { Console.WriteLine("Error linking attachment to work item: " + response.StatusCode); } }
解决方案
问题出在附件上传步骤:Azure DevOps REST API的附件上传端点需要显式通过fileName查询参数指定文件名,仅在请求头的Content-Disposition中设置文件名不足以让平台保存原始文件名,导致下载时默认使用附件ID作为文件名。
修改步骤:
- 在上传附件的请求URL中添加
fileName参数,并用Uri.EscapeDataString转义特殊字符(如空格、中文等),确保文件名正确传递。
修改UploadAttachmentAsync方法中的请求URL:
string requestUrl = $"{OrganizationUrl}{ProjectName}/_apis/wit/attachments?api-version=7.0&fileName={Uri.EscapeDataString(fileName)}";
原理说明:
Azure DevOps会根据URL中的fileName参数存储附件的原始文件名,后续工作项中显示的附件名称、下载时的文件名都会基于这个值。之前的代码仅设置了Content-Disposition头,但该头主要用于HTTP传输阶段的文件名提示,Azure DevOps平台不会以此作为附件的持久化文件名。
修改后,上传的附件会在工作项中显示正确的文件名,下载时也会使用原始文件名,而非附件ID。
内容的提问来源于stack exchange,提问作者Shwetha TO
相关产品推荐
相关产品推荐

