.NET 6迁移.NET 8后Azure Functions队列消息自动转为byte[]问题
问题
将Azure Functions项目从.NET 6迁移至.NET 8后,队列消息处理出现异常:
- .NET 6中可直接将队列消息读取为
string类型,正常执行Base64解码; - 迁移后发送代码未变更,但队列消息默认以
byte[]类型接收。若仍用string作为QueueTrigger参数,会触发**"无法将指定代码页的字节转换为Unicode"错误;使用byte[]虽能处理消息,但会收到"消息体含非UTF-8字节"**的警告。
咨询:是否存在.NET 8或Azure Functions的配置项,可指定队列消息以string类型接收,无需修改发送逻辑?
发送消息代码
var message = JsonSerializer.Serialize(batch); var compressedMessage = Compression.CompressMessage(message); if (compressedMessage.Length > 64 * 1024) { _logger.LogError("Compressed message size exceeds Azure Queue limit."); throw new InvalidOperationException("Message size exceeds Azure Queue limit after compression."); } await queueClient.SendMessageAsync(Convert.ToBase64String(compressedMessage)); _logger.LogInformation($"Batch with {batch.Count} items pushed to queue.");
.NET 6接收函数
public async Task ProcessBatchFromQueue( [QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] string compressedMessageBase64, ILogger log) { try { log.LogInformation("Processing batch from queue..."); var compressedMessage = Convert.FromBase64String(compressedMessageBase64); var decompressedMessage = Compression.DecompressMessage(compressedMessage); var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage); } catch (Exception ex) { log.LogError($"Error: {ex.Message}"); } }
.NET 8接收函数
[Function("ProcessBatchFromQueue")] public async Task ProcessBatchFromQueue([QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] byte[] compressedMessageBase64) { try { _logger.LogInformation("Processing batch from queue..."); string decompressedMessage = Compression.DecompressMessage(compressedMessageBase64); var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage); } catch (Exception ex) { _logger.LogError($"Error: {ex.Message}"); } }
压缩解压逻辑
using System.IO.Compression; public static class Compression { /// <summary> /// Compresses a string using GZip. /// </summary> public static byte[] CompressMessage(string message) { using (var memoryStream = new MemoryStream()) { using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) using (var writer = new StreamWriter(gzipStream)) { writer.Write(message); writer.Flush(); } return memoryStream.ToArray(); } } /// <summary> /// Decompresses a GZip-compressed string. /// </summary> public static string DecompressMessage(byte[] compressedMessage) { using (var memoryStream = new MemoryStream(compressedMessage)) using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) using (var reader = new StreamReader(gzipStream)) { return reader.ReadToEnd(); } } }
警告日志
[2025-02-28T01:37:19.025Z] Batch with 200 items pushed to queue. [2025-02-28T01:37:19.115Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6 [2025-02-28T01:37:19.131Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6 [2025-02-28T01:37:19.135Z] Queue message's body cannot be converted to string because it contains non-UTF8 bytes, message id=d8887de8-f2d8-40cf-8990-555ss7b280d6 [2025-02-28T01:37:19.137Z] Executing 'Functions.ProcessBatchFromQueue' (Reason='New queue message detected on 'test-queue'.', Id=a148187e-9f70-4bb9-b9df-8446d1b337d7) [2025-02-28T01:37:19.139Z] Trigger Details: MessageId: d8887de8-f2d8-40cf-8990-555ss7b280d6, DequeueCount: 1, InsertedOn: 2025-02-28T01:37:19.000+00:00
错误日志
[2025-02-28T02:09:56.143Z] Trigger Details: MessageId: 27ad4e9b-86a1-4e9b-9596-7f697424e58a, DequeueCount: 4, InsertedOn: 2025-02-28T02:09:53.000+00:00 [2025-02-28T02:09:56.148Z] Executed 'Functions.ProcessBatchFromQueue' (Failed, Id=4bb49420-5b7c-43ad-adc4-2870d3a3e382, Duration=7ms) [2025-02-28T02:09:56.150Z] System.Private.CoreLib: Exception while executing function: Functions.ProcessBatchFromQueue. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'compressedMessageBase64'. System.Private.CoreLib: Unable to translate bytes [8B] at index 1 from specified code page to Unicode.
解决方案
方案1:通过配置强制以字符串接收消息
在local.settings.json(本地开发)或Azure门户的应用程序设置中添加以下配置:
{ "Values": { "AzureWebJobsStorage": "...", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", "AzureWebJobsQueue__MessageEncoding": "Base64" } }
该配置会告知QueueTrigger将所有队列消息视为Base64编码的字符串,直接传递给string类型参数,无需自动解码字节流。配置后即可恢复.NET 6的接收逻辑,继续使用string类型参数处理消息。
方案2:调整接收逻辑兼容现有发送代码(无需修改发送端)
如果不想添加全局配置,可在接收函数中使用byte[]参数,手动将字节转换为Base64字符串后按原逻辑处理:
[Function("ProcessBatchFromQueue")] public async Task ProcessBatchFromQueue([QueueTrigger("test-queue", Connection = "AzureWebJobsStorage")] byte[] messageBytes) { try { _logger.LogInformation("Processing batch from queue..."); // 将字节数组转换为Base64字符串,匹配发送端的编码逻辑 string compressedMessageBase64 = Convert.ToBase64String(messageBytes); var compressedMessage = Convert.FromBase64String(compressedMessageBase64); var decompressedMessage = Compression.DecompressMessage(compressedMessage); var batch = JsonSerializer.Deserialize<IReadOnlyCollection<InventoryProduct>>(decompressedMessage); } catch (Exception ex) { _logger.LogError($"Error: {ex.Message}"); } }
这种方式可避免转换错误,同时完全兼容原发送逻辑。
消除"非UTF-8字节"警告
警告是因为SDK会尝试将消息体转换为字符串用于日志记录,即使使用byte[]接收也会触发。可通过配置禁用消息内容日志:
{ "Values": { "AzureWebJobsQueue__LogMessageContent": false } }
内容的提问来源于stack exchange,提问作者Wookappa
相关产品推荐
相关产品推荐

