You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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作为文件名。

修改步骤:

  1. 在上传附件的请求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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:03:17