Azure.Messaging.EventGrid (.NET)
Azure Event Grid 주제, 도메인 및 네임스페이스에 이벤트를 게시하기 위한 클라이언트 라이브러리입니다.
설치
dotnet add package Azure.Messaging.EventGrid
dotnet add package Azure.Messaging.EventGrid.Namespaces
dotnet add package Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents
현재 버전: 4.28.0 (안정화)
환경 변수
EVENT_GRID_TOPIC_ENDPOINT=https://<topic-name>.<region>.eventgrid.azure.net/api/events
EVENT_GRID_TOPIC_KEY=<access-key>
EVENT_GRID_NAMESPACE_ENDPOINT=https://<namespace>.<region>.eventgrid.azure.net
EVENT_GRID_TOPIC_NAME=<topic-name>
EVENT_GRID_SUBSCRIPTION_NAME=<subscription-name>
AZURE_TOKEN_CREDENTIALS=prod
클라이언트 계층 구조
푸시 전송 (주제/도메인)
└── EventGridPublisherClient
├── SendEventAsync(EventGridEvent)
├── SendEventsAsync(IEnumerable<EventGridEvent>)
├── SendEventAsync(CloudEvent)
└── SendEventsAsync(IEnumerable<CloudEvent>)
풀 전송 (네임스페이스)
├── EventGridSenderClient
│ └── SendAsync(CloudEvent)
└── EventGridReceiverClient
├── ReceiveAsync()
├── AcknowledgeAsync()
├── ReleaseAsync()
└── RejectAsync()
인증
API 키 인증
using Azure;
using Azure.Messaging.EventGrid;
EventGridPublisherClient client = new(
new Uri("https://mytopic.eastus-1.eventgrid.azure.net/api/events"),
new AzureKeyCredential("<access-key>"));
Microsoft Entra 토큰 자격 증명
using Azure.Identity;
using Azure.Messaging.EventGrid;
var credential = new DefaultAzureCredential(
DefaultAzureCredential.DefaultEnvironmentVariableName
);
EventGridPublisherClient client = new(
new Uri("https://mytopic.eastus-1.eventgrid.azure.net/api/events"),
credential);
SAS 토큰 인증
string sasToken = EventGridPublisherClient.BuildSharedAccessSignature(
new Uri(topicEndpoint),
DateTimeOffset.UtcNow.AddHours(1),
new AzureKeyCredential(topicKey));
var sasCredential = new AzureSasCredential(sasToken);
EventGridPublisherClient client = new(
new Uri(topicEndpoint),
sasCredential);
이벤트 게시
EventGridEvent 스키마
EventGridPublisherClient client = new(
new Uri(topicEndpoint),
new AzureKeyCredential(topicKey));
EventGridEvent egEvent = new(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: new { OrderId = "12345", Amount = 99.99 });
await client.SendEventAsync(egEvent);
List<EventGridEvent> events = new()
{
new EventGridEvent(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: new OrderData { OrderId = "12345", Amount = 99.99 }),
new EventGridEvent(
subject: "orders/12346",
eventType: "Order.Created",
dataVersion: "1.0",
data: new OrderData { OrderId = "12346", Amount = 149.99 })
};
await client.SendEventsAsync(events);
CloudEvent 스키마
CloudEvent cloudEvent = new(
source: "/orders/system",
type: "Order.Created",
data: new { OrderId = "12345", Amount = 99.99 });
cloudEvent.Subject = "orders/12345";
cloudEvent.Id = Guid.NewGuid().ToString();
cloudEvent.Time = DateTimeOffset.UtcNow;
await client.SendEventAsync(cloudEvent);
List<CloudEvent> cloudEvents = new()
{
new CloudEvent("/orders", "Order.Created", new { OrderId = "1" }),
new CloudEvent("/orders", "Order.Updated", new { OrderId = "2" })
};
await client.SendEventsAsync(cloudEvents);
Event Grid 도메인에 게시
List<EventGridEvent> events = new()
{
new EventGridEvent(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: new { OrderId = "12345" })
{
Topic = "orders-topic"
},
new EventGridEvent(
subject: "inventory/item-1",
eventType: "Inventory.Updated",
dataVersion: "1.0",
data: new { ItemId = "item-1" })
{
Topic = "inventory-topic"
}
};
await client.SendEventsAsync(events);
사용자 지정 직렬화
using System.Text.Json;
var serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
var customSerializer = new JsonObjectSerializer(serializerOptions);
EventGridEvent egEvent = new(
subject: "orders/12345",
eventType: "Order.Created",
dataVersion: "1.0",
data: customSerializer.Serialize(new OrderData { OrderId = "12345" }));
await client.SendEventAsync(egEvent);
풀 전송 (네임스페이스)
네임스페이스 주제로 이벤트 전송
using Azure;
using Azure.Messaging;
using Azure.Messaging.EventGrid.Namespaces;
var senderClient = new EventGridSenderClient(
new Uri(namespaceEndpoint),
topicName,
new AzureKeyCredential(topicKey));
CloudEvent cloudEvent = new("employee_source", "Employee.Created",
new { Name = "John", Age = 30 });
await senderClient.SendAsync(cloudEvent);
await senderClient.SendAsync(new[]
{
new CloudEvent("source", "type", new { Name = "Alice" }),
new CloudEvent("source", "type", new { Name = "Bob" })
});
이벤트 수신 및 처리
var receiverClient = new EventGridReceiverClient(
new Uri(namespaceEndpoint),
topicName,
subscriptionName,
new AzureKeyCredential(topicKey));
ReceiveResult result = await receiverClient.ReceiveAsync(maxEvents: 10);
List<string> lockTokensToAck = new();
List<string> lockTokensToRelease = new();
foreach (ReceiveDetails detail in result.Details)
{
CloudEvent cloudEvent = detail.Event;
string lockToken = detail.BrokerProperties.LockToken;
try
{
Console.WriteLine($"Event: {cloudEvent.Type}, Data: {cloudEvent.Data}");
lockTokensToAck.Add(lockToken);
}
catch (Exception)
{
lockTokensToRelease.Add(lockToken);
}
}
if (lockTokensToAck.Any())
{
await receiverClient.AcknowledgeAsync(lockTokensToAck);
}
if (lockTokensToRelease.Any())
{
await receiverClient.ReleaseAsync(lockTokensToRelease);
}
이벤트 거부 (Dead Letter)
await receiverClient.RejectAsync(new[] { lockToken });
이벤트 소비 (Azure Functions)
EventGridEvent 트리거
using Azure.Messaging.EventGrid;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.EventGrid;
public static class EventGridFunction
{
[FunctionName("ProcessEventGridEvent")]
public static void Run(
[EventGridTrigger] EventGridEvent eventGridEvent,
ILogger log)
{
log.LogInformation($"Event Type: {eventGridEvent.EventType}");
log.LogInformation($"Subject: {eventGridEvent.Subject}");
log.LogInformation($"Data: {eventGridEvent.Data}");
}
}
CloudEvent 트리거
using Azure.Messaging;
using Microsoft.Azure.Functions.Worker;
public class CloudEventFunction
{
[Function("ProcessCloudEvent")]
public void Run(
[EventGridTrigger] CloudEvent cloudEvent,
FunctionContext context)
{
var logger = context.GetLogger("ProcessCloudEvent");
logger.LogInformation($"Event Type: {cloudEvent.Type}");
logger.LogInformation($"Source: {cloudEvent.Source}");
logger.LogInformation($"Data: {cloudEvent.Data}");
}
}
이벤트 구문 분석
EventGridEvent 구문 분석
string json = "...";
EventGridEvent[] events = EventGridEvent.ParseMany(BinaryData.FromString(json));
foreach (EventGridEvent egEvent in events)
{
if (egEvent.TryGetSystemEventData(out object systemEvent))
{
switch (systemEvent)
{
case StorageBlobCreatedEventData blobCreated:
Console.WriteLine($"Blob created: {blobCreated.Url}");
break;
}
}
else
{
var customData = egEvent.Data.ToObjectFromJson<MyCustomData>();
}
}
CloudEvent 구문 분석
CloudEvent[] cloudEvents = CloudEvent.ParseMany(BinaryData.FromString(json));
foreach (CloudEvent cloudEvent in cloudEvents)
{
var data = cloudEvent.Data.ToObjectFromJson<MyEventData>();
Console.WriteLine($"Type: {cloudEvent.Type}, Data: {data}");
}
시스템 이벤트
using Azure.Messaging.EventGrid.SystemEvents;
StorageBlobCreatedEventData blobCreated;
StorageBlobDeletedEventData blobDeleted;
ResourceWriteSuccessEventData resourceCreated;
ResourceDeleteSuccessEventData resourceDeleted;
WebAppUpdatedEventData webAppUpdated;
ContainerRegistryImagePushedEventData imagePushed;
IotHubDeviceCreatedEventData deviceCreated;
주요 유형 참조
| 유형 | 용도 |
|---|
EventGridPublisherClient | 주제/도메인에 게시 |
EventGridSenderClient | 네임스페이스 주제로 전송 |
EventGridReceiverClient | 네임스페이스 구독에서 수신 |
EventGridEvent | Event Grid 네이티브 스키마 |
CloudEvent | CloudEvents 1.0 스키마 |
ReceiveResult | 풀 전송 응답 |
ReceiveDetails | 브로커 속성이 포함된 이벤트 |
BrokerProperties | 잠금 토큰, 전달 횟수 |
이벤트 스키마 비교
| 기능 | EventGridEvent | CloudEvent |
|---|
| 표준 | Azure 전용 | CNCF 표준 |
| 필수 필드 | subject, eventType, dataVersion, data | source, type |
| 확장성 | 제한적 | 확장 속성 |
| 상호 운용성 | Azure 전용 | 플랫폼 간 |
모범 사례
- CloudEvents 사용 — 새로운 구현에는 CloudEvents를 선호합니다 (업계 표준)
- 이벤트 배치 — 효율성을 위해 단일 호출로 여러 이벤트를 전송합니다.
- Entra ID 사용 — 액세스 키보다 관리 ID를 선호합니다.
- 멱등성(Idempotent) 핸들러 — 이벤트가 두 번 이상 전달될 수 있습니다.
- 이벤트 TTL 설정 — 네임스페이스 이벤트의 TTL(Time-to-Live)을 구성합니다.
- 부분 실패 처리 — 이벤트를 개별적으로 확인/릴리스합니다.
- Dead-letter 사용 — 실패한 이벤트에 대해 Dead-letter를 구성합니다.
- 스키마 유효성 검사 — 처리 전에 이벤트 데이터의 유효성을 검사합니다.
오류 처리
using Azure;
try
{
await client.SendEventAsync(cloudEvent);
}
catch (RequestFailedException ex) when (ex.Status == 401)
{
Console.WriteLine("인증 실패 - 자격 증명 확인");
}
catch (RequestFailedException ex) when (ex.Status == 403)
{
Console.WriteLine("권한 부여 실패 - RBAC 권한 확인");
}
catch (RequestFailedException ex) when (ex.Status == 413)
{
Console.WriteLine("페이로드가 너무 큼 - 이벤트당 최대 1MB, 배치 총합 최대 1MB");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Event Grid 오류: {ex.Status} - {ex.Message}");
}
장애 조치 패턴
try
{
var primaryClient = new EventGridPublisherClient(primaryUri, primaryKey);
await primaryClient.SendEventsAsync(events);
}
catch (RequestFailedException)
{
var secondaryClient = new EventGridPublisherClient(secondaryUri, secondaryKey);
await secondaryClient.SendEventsAsync(events);
}
관련 SDK
| SDK | 용도 | 설치 |
|---|
Azure.Messaging.EventGrid | 주제/도메인 (이 SDK) | dotnet add package Azure.Messaging.EventGrid |
Azure.Messaging.EventGrid.Namespaces | 풀 전송 | dotnet add package Azure.Messaging.EventGrid.Namespaces |
Azure.Identity | 인증 | dotnet add package Azure.Identity |
Microsoft.Azure.WebJobs.Extensions.EventGrid | Azure Functions 트리거 | dotnet add package Microsoft.Azure.WebJobs.Extensions.EventGrid |
참조 링크