使用.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
相关产品推荐
相关产品推荐

