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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:40:09