/// <summary> /// Given a single JSON-encoded event, parses the event envelope and returns a CloudEvent. /// </summary> /// <param name="binaryData"> Specifies the instance of <see cref="BinaryData"/>. </param> /// <returns> A <see cref="CloudEvent"/>. </returns> public static CloudEvent ToCloudEvent(this BinaryData binaryData) { // Deserialize JsonElement to single event, parse event envelope properties JsonDocument requestDocument = JsonDocument.Parse(binaryData.ToMemory()); CloudEventInternal cloudEventInternal = CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement); CloudEvent cloudEvent = new CloudEvent( cloudEventInternal.Id, cloudEventInternal.Source, cloudEventInternal.Type, cloudEventInternal.Time, cloudEventInternal.Dataschema, cloudEventInternal.Datacontenttype, cloudEventInternal.Subject, cloudEventInternal.Data, cloudEventInternal.DataBase64); if (cloudEventInternal.AdditionalProperties != null) { foreach (KeyValuePair <string, object> kvp in cloudEventInternal.AdditionalProperties) { cloudEvent.ExtensionAttributes.Add(kvp.Key, kvp.Value); } } return(cloudEvent); }
/// <summary> /// Given a single JSON-encoded event, parses the event envelope and returns a CloudEvent. /// </summary> /// <param name="binaryData"> Specifies the instance of <see cref="BinaryData"/>. </param> /// <returns> A <see cref="CloudEvent"/>. </returns> public static CloudEvent ToCloudEvent(this BinaryData binaryData) { // Deserialize JsonElement to single event, parse event envelope properties JsonDocument requestDocument = JsonDocument.Parse(binaryData.Bytes); CloudEventInternal cloudEventInternal = CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement); // Case where Data and Type are null - cannot pass null Type into CloudEvent constructor if (cloudEventInternal.Type == null) { cloudEventInternal.Type = ""; } CloudEvent cloudEvent = new CloudEvent( cloudEventInternal.Source, cloudEventInternal.Type) { Id = cloudEventInternal.Id, Time = cloudEventInternal.Time, DataBase64 = cloudEventInternal.DataBase64, DataSchema = cloudEventInternal.Dataschema, DataContentType = cloudEventInternal.Datacontenttype, Subject = cloudEventInternal.Subject, SerializedData = cloudEventInternal.Data }; if (cloudEventInternal.AdditionalProperties != null) { foreach (KeyValuePair <string, object> kvp in cloudEventInternal.AdditionalProperties) { cloudEvent.ExtensionAttributes.Add(kvp.Key, kvp.Value); } } return(cloudEvent); }
/// <summary> /// Given JSON-encoded events, parses the event envelope and returns an array of CloudEvents. /// </summary> /// <param name="requestContent"> The JSON-encoded representation of either a single event or an array or events, in the CloudEvent schema. </param> /// <returns> A list of <see cref="CloudEvent"/>. </returns> public static CloudEvent[] Parse(string requestContent) { List <CloudEventInternal> cloudEventsInternal = new List <CloudEventInternal>(); List <CloudEvent> cloudEvents = new List <CloudEvent>(); JsonDocument requestDocument = JsonDocument.Parse(requestContent); // Parse JsonElement into separate events, deserialize event envelope properties if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement)); } else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) { foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(property)); } } foreach (CloudEventInternal cloudEventInternal in cloudEventsInternal) { cloudEvents.Add(new CloudEvent(cloudEventInternal)); } return(cloudEvents.ToArray()); }
/// <summary> /// Given JSON-encoded events, parses the event envelope and returns an array of CloudEvents. /// </summary> /// <param name="requestContent"> The JSON-encoded representation of either a single event or an array or events, in the CloudEvent schema. </param> /// <returns> A list of <see cref="CloudEvent"/>. </returns> public static CloudEvent[] Parse(string requestContent) { List <CloudEventInternal> cloudEventsInternal = new List <CloudEventInternal>(); List <CloudEvent> cloudEvents = new List <CloudEvent>(); JsonDocument requestDocument = JsonDocument.Parse(requestContent); // Parse JsonElement into separate events, deserialize event envelope properties if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement)); } else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) { foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(property)); } } foreach (CloudEventInternal cloudEventInternal in cloudEventsInternal) { // Case where Data and Type are null - cannot pass null Type into CloudEvent constructor if (cloudEventInternal.Type == null) { cloudEventInternal.Type = ""; } CloudEvent cloudEvent = new CloudEvent( cloudEventInternal.Source, cloudEventInternal.Type) { Id = cloudEventInternal.Id, Time = cloudEventInternal.Time, DataBase64 = cloudEventInternal.DataBase64, DataSchema = cloudEventInternal.Dataschema, DataContentType = cloudEventInternal.Datacontenttype, Subject = cloudEventInternal.Subject, SerializedData = cloudEventInternal.Data }; if (cloudEventInternal.AdditionalProperties != null) { foreach (KeyValuePair <string, object> kvp in cloudEventInternal.AdditionalProperties) { cloudEvent.ExtensionAttributes.Add(kvp.Key, kvp.Value); } } cloudEvents.Add(cloudEvent); } return(cloudEvents.ToArray()); }
internal CloudEvent(CloudEventInternal cloudEventInternal) { // we only validate that the type is required when deserializing since the service allows sending a CloudEvent without a Source. Argument.AssertNotNull(cloudEventInternal.Type, nameof(cloudEventInternal.Type)); Id = cloudEventInternal.Id; Source = cloudEventInternal.Source; Type = cloudEventInternal.Type; Time = cloudEventInternal.Time; DataSchema = cloudEventInternal.Dataschema; DataContentType = cloudEventInternal.Datacontenttype; Subject = cloudEventInternal.Subject; SerializedData = cloudEventInternal.Data; DataBase64 = cloudEventInternal.DataBase64; ExtensionAttributes = new Dictionary <string, object>(cloudEventInternal.AdditionalProperties); }
/// <summary> /// Given JSON-encoded events, parses the event envelope and returns an array of CloudEvents. /// </summary> /// <param name="requestContent"> The JSON-encoded representation of either a single event or an array or events, in the CloudEvent schema. </param> /// <returns> A list of <see cref="CloudEvent"/>. </returns> public static CloudEvent[] Parse(string requestContent) { List <CloudEventInternal> cloudEventsInternal = new List <CloudEventInternal>(); List <CloudEvent> cloudEvents = new List <CloudEvent>(); JsonDocument requestDocument = JsonDocument.Parse(requestContent); // Parse JsonElement into separate events, deserialize event envelope properties if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement)); } else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) { foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(property)); } } foreach (CloudEventInternal cloudEventInternal in cloudEventsInternal) { CloudEvent cloudEvent = new CloudEvent( cloudEventInternal.Id, cloudEventInternal.Source, cloudEventInternal.Type, cloudEventInternal.Time, cloudEventInternal.Dataschema, cloudEventInternal.Datacontenttype, cloudEventInternal.Subject, cloudEventInternal.Data, cloudEventInternal.DataBase64); if (cloudEventInternal.AdditionalProperties != null) { foreach (KeyValuePair <string, object> kvp in cloudEventInternal.AdditionalProperties) { cloudEvent.ExtensionAttributes.Add(kvp.Key, kvp.Value); } } cloudEvents.Add(cloudEvent); } return(cloudEvents.ToArray()); }
private static List <CloudEvent> DeserializeRequest(Request request) { var content = request.Content as Utf8JsonRequestContent; var stream = new MemoryStream(); content.WriteTo(stream, CancellationToken.None); stream.Position = 0; JsonDocument requestDocument = JsonDocument.Parse(stream); var cloudEvents = new List <CloudEvent>(); // Parse JsonElement into separate events, deserialize event envelope properties if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) { cloudEvents.Add(new CloudEvent(CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement))); } else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) { foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEvents.Add(new CloudEvent(CloudEventInternal.DeserializeCloudEventInternal(property))); } } return(cloudEvents); }
/// <summary> /// Given JSON-encoded events, parses the event envelope and returns an array of CloudEvents. /// </summary> /// <param name="requestContent"> The JSON-encoded representation of either a single event or an array or events, in the CloudEvent schema. </param> /// <returns> A list of <see cref="CloudEvent"/>. </returns> public static CloudEvent[] Parse(string requestContent) { Argument.AssertNotNull(requestContent, nameof(requestContent)); CloudEvent[] cloudEvents = null; JsonDocument requestDocument = JsonDocument.Parse(requestContent); // Parse JsonElement into separate events, deserialize event envelope properties if (requestDocument.RootElement.ValueKind == JsonValueKind.Object) { cloudEvents = new CloudEvent[1]; cloudEvents[0] = (new CloudEvent(CloudEventInternal.DeserializeCloudEventInternal(requestDocument.RootElement))); } else if (requestDocument.RootElement.ValueKind == JsonValueKind.Array) { cloudEvents = new CloudEvent[requestDocument.RootElement.GetArrayLength()]; int i = 0; foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEvents[i++] = new CloudEvent(CloudEventInternal.DeserializeCloudEventInternal(property)); } } return(cloudEvents ?? Array.Empty <CloudEvent>()); }
/// <summary> Publishes a batch of CloudEvents to an Azure Event Grid topic. </summary> /// <param name="events"> An array of events to be published to Event Grid. </param> /// <param name="async">Whether to invoke the operation asynchronously.</param> /// <param name="cancellationToken"> The cancellation token to use. </param> private async Task <Response> SendCloudEventsInternal(IEnumerable <CloudEvent> events, bool async, CancellationToken cancellationToken = default) { using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(EventGridPublisherClient)}.{nameof(SendEvents)}"); scope.Start(); try { // List of events cannot be null Argument.AssertNotNull(events, nameof(events)); List <CloudEventInternal> eventsWithSerializedPayloads = new List <CloudEventInternal>(); foreach (CloudEvent cloudEvent in events) { // Individual events cannot be null Argument.AssertNotNull(cloudEvent, nameof(cloudEvent)); CloudEventInternal newCloudEvent = new CloudEventInternal( cloudEvent.Id, cloudEvent.Source, cloudEvent.Type, "1.0") { Time = cloudEvent.Time, DataBase64 = cloudEvent.DataBase64, Datacontenttype = cloudEvent.DataContentType, Dataschema = cloudEvent.DataSchema, Subject = cloudEvent.Subject }; foreach (KeyValuePair <string, object> kvp in cloudEvent.ExtensionAttributes) { newCloudEvent.Add(kvp.Key, new CustomModelSerializer(kvp.Value, _dataSerializer, cancellationToken)); } // The 'Data' property is optional for CloudEvents // Additionally, if the type of data is binary, 'Data' will not be populated (data will be stored in 'DataBase64' instead) if (cloudEvent.Data != null) { JsonDocument data = SerializeObjectToJsonDocument(cloudEvent.Data, cloudEvent.Data.GetType(), cancellationToken); newCloudEvent.Data = data.RootElement; } eventsWithSerializedPayloads.Add(newCloudEvent); } if (async) { // Publish asynchronously if called via an async path return(await _serviceRestClient.PublishCloudEventEventsAsync( _hostName, eventsWithSerializedPayloads, cancellationToken).ConfigureAwait(false)); } else { return(_serviceRestClient.PublishCloudEventEvents( _hostName, eventsWithSerializedPayloads, cancellationToken)); } } catch (Exception e) { scope.Failed(e); throw; } }
/// <summary> Publishes a batch of CloudEvents to an Azure Event Grid topic. </summary> /// <param name="events"> An array of events to be published to Event Grid. </param> /// <param name="async">Whether to invoke the operation asynchronously</param> /// <param name="cancellationToken"> The cancellation token to use. </param> private async Task <Response> PublishCloudEventsInternal(IEnumerable <CloudEvent> events, bool async, CancellationToken cancellationToken = default) { using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(EventGridPublisherClient)}.{nameof(PublishCloudEvents)}"); scope.Start(); try { // List of events cannot be null Argument.AssertNotNull(events, nameof(events)); List <CloudEventInternal> eventsWithSerializedPayloads = new List <CloudEventInternal>(); foreach (CloudEvent cloudEvent in events) { // Individual events cannot be null Argument.AssertNotNull(cloudEvent, nameof(cloudEvent)); CloudEventInternal newCloudEvent = new CloudEventInternal( cloudEvent.Id, cloudEvent.Source, cloudEvent.Type, cloudEvent.SpecVersion) { Time = cloudEvent.Time, Datacontenttype = cloudEvent.DataContentType, Dataschema = cloudEvent.DataSchema, Subject = cloudEvent.Subject }; foreach (KeyValuePair <string, object> kvp in cloudEvent.ExtensionAttributes) { newCloudEvent.Add(kvp.Key, new EventGridSerializer(kvp.Value, _serializer, cancellationToken)); } // The 'Data' property is optional for CloudEvents if (cloudEvent.Data != null) { if (cloudEvent.Data is IEnumerable <byte> enumerable) { newCloudEvent.DataBase64 = Convert.ToBase64String(enumerable.ToArray()); } else if (cloudEvent.Data is ReadOnlyMemory <byte> memory) { newCloudEvent.DataBase64 = Convert.ToBase64String(memory.ToArray()); } else { newCloudEvent.Data = new EventGridSerializer( cloudEvent.Data, _serializer, cancellationToken); } } eventsWithSerializedPayloads.Add(newCloudEvent); } if (async) { // Publish asynchronously if called via an async path return(await _serviceRestClient.PublishCloudEventEventsAsync( _hostName, eventsWithSerializedPayloads, cancellationToken).ConfigureAwait(false)); } else { return(_serviceRestClient.PublishCloudEventEvents( _hostName, eventsWithSerializedPayloads, cancellationToken)); } } catch (Exception e) { scope.Failed(e); throw; } }
private async Task <CloudEvent[]> DeserializeCloudEventsInternal(string requestContent, bool async, CancellationToken cancellationToken = default) { List <CloudEventInternal> cloudEventsInternal = new List <CloudEventInternal>(); List <CloudEvent> cloudEvents = new List <CloudEvent>(); // Deserialize raw JSON string into separate events, deserialize event envelope properties JsonDocument requestDocument = await ParseJsonToDocument(requestContent, async, cancellationToken).ConfigureAwait(false); foreach (JsonElement property in requestDocument.RootElement.EnumerateArray()) { cloudEventsInternal.Add(CloudEventInternal.DeserializeCloudEventInternal(property)); } // Deserialize 'Data' property from JsonElement for each event foreach (CloudEventInternal cloudEventInternal in cloudEventsInternal) { object cloudEventData = null; if (cloudEventInternal.DataBase64 != null) { cloudEventData = Convert.FromBase64String(cloudEventInternal.DataBase64); } else { JsonElement?dataElement = cloudEventInternal.Data; if (dataElement.HasValue && dataElement.Value.ValueKind != JsonValueKind.Null) { // Reserialize JsonElement to stream MemoryStream dataStream = SerializePayloadToStream(dataElement, cancellationToken); // First, let's attempt to find the mapping for the event type in the custom event mapping. if (_customEventTypeMappings.TryGetValue(cloudEventInternal.Type, out Type typeOfEventData)) { if (!TryGetPrimitiveFromJsonElement(dataElement.Value, out cloudEventData)) { if (async) { cloudEventData = await _dataSerializer.DeserializeAsync(dataStream, typeOfEventData, cancellationToken).ConfigureAwait(false); } else { cloudEventData = _dataSerializer.Deserialize(dataStream, typeOfEventData, cancellationToken); } } } // If a custom mapping doesn't exist, let's attempt to find the mapping for the deserialization function in the system event type mapping. else if (SystemEventTypeMappings.SystemEventDeserializers.TryGetValue(cloudEventInternal.Type, out Func <JsonElement, object> systemDeserializationFunction)) { cloudEventData = systemDeserializationFunction(dataElement.Value); } // If no custom mapping was added, either return a primitive/string, or an object wrapped as BinaryData else { // If event data is not a primitive/string, return as BinaryData if (!TryGetPrimitiveFromJsonElement(dataElement.Value, out cloudEventData)) { cloudEventData = BinaryData.FromStream(dataStream); } } } else // Event has null data { cloudEventData = null; cloudEventInternal.Type = ""; } } cloudEvents.Add(new CloudEvent( cloudEventInternal.Source, cloudEventInternal.Type) { Id = cloudEventInternal.Id, Data = cloudEventData, Time = cloudEventInternal.Time, DataSchema = cloudEventInternal.Dataschema, DataContentType = cloudEventInternal.Datacontenttype, Subject = cloudEventInternal.Subject }); } return(cloudEvents.ToArray()); }