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

使用.NET向Append Blob追加数据时JSON数组格式错误的修复方法

问题描述

现有代码通过Azure Functions分批读取用户数据并追加到Blob存储中,但每次序列化整个用户列表并直接追加,导致Blob中生成了多个JSON数组拼接的无效格式(如[...][...])。需要修改代码,将输出修正为单个合法JSON数组或每行一个用户对象的文本格式。

现有代码

函数实现

[FunctionName(nameof(MembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] MembersReaderRequest request)
{
    
    var response = await getFirstMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "a" } };
    var fileName = "a.json";
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        await JsonSerializer.SerializeAsync(logEntryStream, users);
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

[FunctionName(nameof(SubsequentMembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] SubsequentMembersReaderRequest request)
{       
    var response = await getNextMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "b" } };
     var fileName = "a.json";
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        await JsonSerializer.SerializeAsync(logEntryStream, response.Users);
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

Blob追加方法

public async Task AppendDataToBlobAsync (MemoryStream logEntryStream, string logBlobName)
{
    var appendBlobClient = _containerClient.GetAppendBlobClient(logBlobName);

    await appendBlobClient.CreateIfNotExistsAsync();
    logEntryStream.Position = 0;

    var maxBlockSize = appendBlobClient.AppendBlobMaxAppendBlockBytes;
    var bytesLeft = logEntryStream.Length;
    var buffer = new byte[maxBlockSize];
    while (bytesLeft > 0)
    {
        var blockSize = (int)Math.Min(bytesLeft, maxBlockSize);
        var bytesRead = await logEntryStream.ReadAsync(buffer.AsMemory(0, blockSize));
        await using (MemoryStream memoryStream = new MemoryStream(buffer, 0, bytesRead))
        {
            await appendBlobClient.AppendBlockAsync(memoryStream);
        }
        bytesLeft -= bytesRead;
    }
}

当前Blob无效格式

[
    {
        
        "UserPrincipalName": "a"
        
    }
][
    {
        
        "UserPrincipalName": "b"
        
    }
][
    {
       
        "UserPrincipalName": "b"
        
    }
]

期望格式

合法JSON数组格式

[
    {
        
        "UserPrincipalName": "a"
        
    },
    {
        
        "UserPrincipalName": "b"
    },
    {
        
        "UserPrincipalName": "b"
    }
]

每行一个对象的文本格式

{
        
        "UserPrincipalName": "a"
        
    }
    {
        
        "UserPrincipalName": "b"
    }
    {
        
        "UserPrincipalName": "c"
    }

解决方案

方案一:生成单个合法JSON数组

核心思路:首次写入时生成数组开头和第一个元素,后续写入仅追加分隔符和新元素,分页完成后补充数组结尾。

修改后的函数代码

[FunctionName(nameof(MembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] MembersReaderRequest request)
{
    var response = await getFirstMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "a" } };
    var fileName = "a.json";
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        // 首次写入:生成数组开头 + 第一个用户对象
        await logEntryStream.WriteAsync(Encoding.UTF8.GetBytes("[\n    "));
        var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
        await JsonSerializer.SerializeAsync(logEntryStream, response.Users[0], jsonOptions);
        
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

[FunctionName(nameof(SubsequentMembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] SubsequentMembersReaderRequest request)
{
    var response = await getNextMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "b" } };
    var fileName = "a.json";
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
        foreach (var user in response.Users)
        {
            // 先写入分隔符,再序列化单个用户对象
            await logEntryStream.WriteAsync(Encoding.UTF8.GetBytes(",\n    "));
            await JsonSerializer.SerializeAsync(logEntryStream, user, jsonOptions);
        }
        
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

分页结束时补充数组结尾

// 所有分页读取完成后调用此方法
public async Task FinalizeJsonBlobAsync(string logBlobName)
{
    var appendBlobClient = _containerClient.GetAppendBlobClient(logBlobName);
    await appendBlobClient.AppendBlockAsync(new MemoryStream(Encoding.UTF8.GetBytes("\n]")));
}

方案二:生成每行一个对象的文本格式

核心思路:每次写入时仅序列化单个用户对象,用换行分隔,无需数组包裹。

修改后的函数代码

[FunctionName(nameof(MembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] MembersReaderRequest request)
{
    var response = await getFirstMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "a" } };
    var fileName = "a.txt"; // 改用txt后缀
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
        foreach (var user in response.Users)
        {
            await JsonSerializer.SerializeAsync(logEntryStream, user, jsonOptions);
            // 用换行分隔多个对象
            await logEntryStream.WriteAsync(Encoding.UTF8.GetBytes("\n\n"));
        }
        
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

[FunctionName(nameof(SubsequentMembersReaderFunction))]
public async Task<string> GetMembersAsync([ActivityTrigger] SubsequentMembersReaderRequest request)
{
    var response = await getNextMembersAsync(request.NextPageUrl);
    response.Users = new List<AzureADUser> { new AzureADUser { UserPrincipalName = "b" } };
    var fileName = "a.txt";
    using (MemoryStream logEntryStream = new MemoryStream())
    {
        var jsonOptions = new JsonSerializerOptions { WriteIndented = true };
        foreach (var user in response.Users)
        {
            await JsonSerializer.SerializeAsync(logEntryStream, user, jsonOptions);
            await logEntryStream.WriteAsync(Encoding.UTF8.GetBytes("\n\n"));
        }
        
        logEntryStream.Position = 0;
        await AppendDataToBlobAsync(logEntryStream, fileName);
    }
    return response.NextPageUrl;
}

内容的提问来源于stack exchange,提问作者user989988

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:13:18