C# Azure Function整合:SAS令牌生成与Blob文件读写问题
Azure Function整合SAS令牌生成与Blob文档读写问题
我是C#新手,正在开发Azure Function,用于生成SAS令牌并读取、修改Blob存储中的.docx文件。目前已有两个分别完成对应任务的函数,但尝试将它们整合为一个函数时遇到无法解决的问题,相关代码如下:
[FunctionName("SasTokenFunction")] public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req) { string connectionString = Environment.GetEnvironmentVariable("AzureStorage"); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); CloudBlobClient client = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = client.GetContainerReference("formsample"); SharedAccessBlobPolicy accessPolicy = new SharedAccessBlobPolicy { SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30), Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read }; string sasUriToken = $"{container.Uri}{container.GetSharedAccessSignature(accessPolicy)}"; // return the SAS Token to the client app GetUserDelegationSasBlobwithcontent(); return (ActionResult)new OkObjectResult(sasUriToken); } public static async void GetUserDelegationSasBlobwithcontent() { string storageAccountUriString = $"https://formsample5.blob.core.windows.net"; var credential = new DefaultAzureCredential(); BlobServiceClient blobServiceClient = new BlobServiceClient(new Uri(storageAccountUriString), credential); UserDelegationKey userDelegationKey = blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(1)); BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient("sample"); //container name BlobClient blobClient = blobContainerClient.GetBlobClient("Sample.docx"); // Get a user delegation key var sasBuilder = new BlobSasBuilder() { BlobContainerName = blobClient.BlobContainerName, BlobName = blobClient.Name, Resource = "b", // b for blob, c for container StartsOn = DateTimeOffset.UtcNow, ExpiresOn = DateTimeOffset.UtcNow.AddHours(4), }; sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write); // read permissions string sasToken = sasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName).ToString(); Console.WriteLine("SAS-Token {0}", sasToken); Uri blobUri = new Uri(blobClient.Uri + "?" + sasToken); BlobClient sasBlobClient = new BlobClient(blobUri); BlobDownloadInfo download = sasBlobClient.Download(); var content = download.Content; using (var streamReader = new StreamReader(content)) { while (!streamReader.EndOfStream) { string line = await streamReader.ReadLineAsync(); Console.WriteLine("\nBlob-contents:{0}", line); } } }
代码核心问题点
- 异步调用未等待:
GetUserDelegationSasBlobwithcontent是async void方法,调用时未加await,会导致方法在后台异步执行,函数直接返回响应,可能引发未捕获异常或操作未完成。 - 新旧SDK混用:同时使用旧版
CloudStorageAccount系列API和新版BlobServiceClient系列API,逻辑冗余,且两种SAS的权限、有效期设置不统一。 - Docx读取方式错误:
.docx是二进制OOXML格式文件,直接用StreamReader读取会得到乱码,需用专门的文档处理库解析。 - 资源管理不规范:部分Blob客户端实例未用
using包裹,可能导致资源泄漏。
修正后的整合代码示例
using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Sas; using Azure.Storage; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System.IO; [FunctionName("SasTokenAndBlobProcessFunction")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, ILogger log) { // 生成容器级SAS令牌(统一使用新版SDK) string connectionString = Environment.GetEnvironmentVariable("AzureStorage"); BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient("formsample"); var containerSasBuilder = new BlobSasBuilder() { BlobContainerName = containerClient.Name, Resource = "c", // c表示容器 StartsOn = DateTimeOffset.UtcNow, ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(30) }; containerSasBuilder.SetPermissions(BlobContainerSasPermissions.Read | BlobContainerSasPermissions.Write); var accountKey = (await blobServiceClient.GetAccountInfoAsync()).Value.PrimaryKey; string containerSasToken = containerSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(blobServiceClient.AccountName, accountKey)).ToString(); string containerSasUri = $"{containerClient.Uri}?{containerSasToken}"; // 读取并处理指定docx文件 await ProcessDocxBlob(log, blobServiceClient); // 返回SAS令牌给客户端 return new OkObjectResult(new { ContainerSasUri = containerSasUri }); } private static async Task ProcessDocxBlob(ILogger log, BlobServiceClient blobServiceClient) { BlobContainerClient sampleContainer = blobServiceClient.GetBlobContainerClient("sample"); BlobClient docxBlobClient = sampleContainer.GetBlobClient("Sample.docx"); // 生成Blob级用户委托SAS(基于AAD授权) UserDelegationKey delegationKey = await blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddHours(4)); var blobSasBuilder = new BlobSasBuilder() { BlobContainerName = sampleContainer.Name, BlobName = docxBlobClient.Name, Resource = "b", // b表示Blob StartsOn = DateTimeOffset.UtcNow, ExpiresOn = DateTimeOffset.UtcNow.AddHours(4) }; blobSasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write); string blobSasToken = blobSasBuilder.ToSasQueryParameters(delegationKey, blobServiceClient.AccountName).ToString(); BlobClient sasBlobClient = new BlobClient(new Uri($"{docxBlobClient.Uri}?{blobSasToken}")); // 下载并处理docx内容 using (MemoryStream stream = new MemoryStream()) { await sasBlobClient.DownloadToAsync(stream); stream.Position = 0; // 使用OpenXML SDK读取并修改文档 using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true)) { MainDocumentPart mainPart = wordDoc.MainDocumentPart; if (mainPart != null) { string text = mainPart.Document.Body.InnerText; log.LogInformation("docx内容:{Text}", text); // 示例:添加新段落 Paragraph para = new Paragraph(new Run(new Text("新增的内容"))); mainPart.Document.Body.AppendChild(para); mainPart.Document.Save(); } } // 将修改后的内容上传回Blob stream.Position = 0; await sasBlobClient.UploadAsync(stream, overwrite: true); } }
额外说明
- 需安装NuGet包:
Azure.Storage.Blobs、DocumentFormat.OpenXml - 用户委托SAS需确保Function身份拥有存储账户的
Storage Blob Data Contributor角色 - 生产环境建议将日志输出替换为业务逻辑处理
内容的提问来源于stack exchange,提问作者Jeanpaul
相关产品推荐
相关产品推荐

