.NET 8独立模式Azure函数EventGridTrigger订阅配置问题
.NET 8独立模式Azure函数Event Grid触发器部署后订阅不可见的解决方法
排查与解决步骤
1. 确认函数部署状态
- 登录Azure门户进入目标函数应用,查看「函数」列表,确认
BlobTriggerFunction已成功部署并处于运行状态。若列表无此函数,前往「部署中心」查看日志,排查编译或发布失败原因。 - 在「配置」→「常规设置」中,确认运行时堆栈为
.NET 8,运行模式为「独立」。
2. 验证Event Grid扩展配置
独立模式下需确保host.json正确配置Event Grid扩展:
{ "version": "2.0", "extensions": { "eventGrid": { "batchProcessing": false, "eventTypes": [ "Microsoft.Storage.BlobCreated" ] } } }
3. 检查权限与身份配置
- 若使用系统托管身份,需为该身份分配「Event Grid订阅者」角色,确保其有权接收事件。
- 直接通过函数URL测试:在函数的「代码+测试」页面获取触发URL,用Postman发送模拟Event Grid事件请求,验证函数是否响应。示例请求体:
[ { "id": "12345", "eventType": "Microsoft.Storage.BlobCreated", "subject": "/blobServices/default/containers/primary/blobs/test.json", "eventTime": "2024-05-20T12:00:00Z", "data": { "Url": "https://yourstorageaccount.blob.core.windows.net/primary/test.json", "ContentType": "application/json" }, "dataVersion": "1.0", "metadataVersion": "1", "topic": "/subscriptions/your-sub-id/resourceGroups/your-rg/providers/Microsoft.Storage/storageAccounts/yourstorageaccount" } ]
4. 正确创建Event Grid订阅
避免通过「测试主题」查找函数,直接从存储账户创建订阅:
- 进入存储账户→「事件」→「+ 事件订阅」
- 自定义订阅名称,选择事件类型为「BlobCreated」
- 终点类型选「Azure 函数」,再选择目标函数应用与
BlobTriggerFunction
代码优化建议
原代码逻辑可行,以下是可靠性优化点:
- 改用
Uri解析Blob URL,避免字符串分割的不可靠性:
var blobUri = new Uri(blobCreatedData.Url); var sourceContainerName = blobUri.Segments[2].TrimEnd('/'); var sourceBlobName = string.Join("", blobUri.Segments.Skip(3));
- 添加异常捕获,确保错误可追踪:
try { // 原有业务逻辑 } catch (Exception ex) { _logger.LogError(ex, "处理Event Grid事件时发生错误"); throw; }
优化后完整代码
using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; using Azure.Storage.Blobs; using System.Text.Json; using CsvHelper; using System.Globalization; using Azure.Messaging.EventGrid; using System; public class BlobTriggerFunction { private readonly ILogger _logger; private readonly BlobServiceClient _blobServiceClient; public BlobTriggerFunction(ILoggerFactory loggerFactory, BlobServiceClient blobServiceClient) { _logger = loggerFactory.CreateLogger<BlobTriggerFunction>(); _blobServiceClient = blobServiceClient; } [Function("BlobTriggerFunction")] public async Task Run([EventGridTrigger] EventGridEvent eventGridEvent) { _logger.LogInformation($"Event Grid trigger function processed an event: {eventGridEvent.EventType}"); if (eventGridEvent.EventType != "Microsoft.Storage.BlobCreated") { _logger.LogInformation($"Ignoring event type: {eventGridEvent.EventType}"); return; } try { var blobCreatedData = eventGridEvent.Data.ToObjectFromJson<BlobCreatedEventData>(); var blobUri = new Uri(blobCreatedData.Url); var sourceContainerName = blobUri.Segments[2].TrimEnd('/'); var sourceBlobName = string.Join("", blobUri.Segments.Skip(3)); var destinationContainerName = "secondary"; var destinationBlobName = Path.ChangeExtension(sourceBlobName, ".csv"); var sourceBlobClient = _blobServiceClient.GetBlobContainerClient(sourceContainerName).GetBlobClient(sourceBlobName); var destinationBlobClient = _blobServiceClient.GetBlobContainerClient(destinationContainerName).GetBlobClient(destinationBlobName); // Download the source blob content using var sourceStream = await sourceBlobClient.OpenReadAsync(); using var streamReader = new StreamReader(sourceStream); var jsonContent = await streamReader.ReadToEndAsync(); // Parse JSON and convert to CSV var jsonArray = JsonSerializer.Deserialize<List<Dictionary<string, JsonElement>>>(jsonContent); using var memoryStream = new MemoryStream(); using var writer = new StreamWriter(memoryStream); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); if (jsonArray?.Any() == true) { var headers = jsonArray[0].Keys.ToArray(); foreach (var header in headers) { csv.WriteField(header); } csv.NextRecord(); foreach (var item in jsonArray) { foreach (var header in headers) { if (item.TryGetValue(header, out JsonElement value)) { csv.WriteField(value.ToString()); } else { csv.WriteField(string.Empty); } } csv.NextRecord(); } } writer.Flush(); memoryStream.Position = 0; // Upload the CSV to the destination container await destinationBlobClient.UploadAsync(memoryStream, true); _logger.LogInformation($"CSV file created and uploaded: {destinationBlobName}"); } catch (Exception ex) { _logger.LogError(ex, "处理BlobCreated事件时发生未预期错误"); throw; } } } public class BlobCreatedEventData { public string Api { get; set; } public string ClientRequestId { get; set; } public string RequestId { get; set; } public string ETag { get; set; } public string ContentType { get; set; } public int ContentLength { get; set; } public string BlobType { get; set; } public string Url { get; set; } public string Sequencer { get; set; } public StorageDiagnostics StorageDiagnostics { get; set; } } public class StorageDiagnostics { public string BatchId { get; set; } }
内容的提问来源于stack exchange,提问作者Bridgette Ryan
相关产品推荐
相关产品推荐

