CloudEventConverter
A custom converter that attributes the CloudEvent type.
This allows System.Text.Json to serialize and deserialize CloudEvents by default.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Azure.Messaging
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This utilizes reflection-based JSON serialization and deserialization which is not compatible with trimming.")]
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("This utilizes reflection-based JSON serialization and deserialization which is not compatible with trimming.")]
internal class CloudEventConverter : JsonConverter<CloudEvent>
{
public override CloudEvent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader))
return DeserializeCloudEvent(jsonDocument.RootElement, false);
}
internal static CloudEvent DeserializeCloudEvent(JsonElement element, bool skipValidation)
{
CloudEvent cloudEvent = new CloudEvent();
foreach (JsonProperty item in element.EnumerateObject()) {
JsonElement element2;
if (item.NameEquals("id")) {
element2 = item.Value;
if (element2.ValueKind != JsonValueKind.Null) {
CloudEvent cloudEvent2 = cloudEvent;
element2 = item.Value;
cloudEvent2.Id = element2.GetString();
}
} else if (item.NameEquals("source")) {
element2 = item.Value;
if (element2.ValueKind != JsonValueKind.Null) {
CloudEvent cloudEvent3 = cloudEvent;
element2 = item.Value;
cloudEvent3.Source = element2.GetString();
}
} else if (item.NameEquals("data")) {
cloudEvent.Data = new BinaryData((object)item.Value, (JsonSerializerOptions)null, (Type)null);
cloudEvent.DataFormat = CloudEventDataFormat.Json;
} else if (item.NameEquals("data_base64")) {
element2 = item.Value;
if (element2.ValueKind != JsonValueKind.Null) {
CloudEvent cloudEvent4 = cloudEvent;
element2 = item.Value;
cloudEvent4.Data = BinaryData.FromBytes(element2.GetBytesFromBase64());
cloudEvent.DataFormat = CloudEventDataFormat.Binary;
}
} else if (item.NameEquals("type")) {
element2 = item.Value;
if (element2.ValueKind != JsonValueKind.Null) {
CloudEvent cloudEvent5 = cloudEvent;
element2 = item.Value;
cloudEvent5.Type = element2.GetString();
}
} else if (item.NameEquals("time")) {
element2 = item.Value;
if (element2.ValueKind != JsonValueKind.Null) {
CloudEvent cloudEvent6 = cloudEvent;
element2 = item.Value;
cloudEvent6.Time = element2.GetDateTimeOffset();
}
} else if (item.NameEquals("specversion")) {
CloudEvent cloudEvent7 = cloudEvent;
element2 = item.Value;
cloudEvent7.SpecVersion = element2.GetString();
} else if (item.NameEquals("dataschema")) {
CloudEvent cloudEvent8 = cloudEvent;
element2 = item.Value;
cloudEvent8.DataSchema = element2.GetString();
} else if (item.NameEquals("datacontenttype")) {
CloudEvent cloudEvent9 = cloudEvent;
element2 = item.Value;
cloudEvent9.DataContentType = element2.GetString();
} else if (item.NameEquals("subject")) {
CloudEvent cloudEvent10 = cloudEvent;
element2 = item.Value;
cloudEvent10.Subject = element2.GetString();
} else if (!skipValidation) {
IDictionary<string, object> extensionAttributes = cloudEvent.ExtensionAttributes;
string name = item.Name;
element2 = item.Value;
extensionAttributes.Add(name, GetObject(ref element2));
} else {
CloudEventExtensionAttributes<string, object> obj = (CloudEventExtensionAttributes<string, object>)cloudEvent.ExtensionAttributes;
string name2 = item.Name;
element2 = item.Value;
obj.AddWithoutValidation(name2, GetObject(ref element2));
}
}
if (!skipValidation) {
if (cloudEvent.Source == null)
throw new ArgumentException("The source property must be specified in each CloudEvent. " + Environment.NewLine + "The `skipValidation` parameter can be set to 'true' in the CloudEvent.Parse or CloudEvent.ParseEvents method to skip this validation.");
if (cloudEvent.Type == null)
throw new ArgumentException("The type property must be specified in each CloudEvent. " + Environment.NewLine + "The `skipValidation` parameter can be set to 'true' in the CloudEvent.Parse or CloudEvent.ParseEvents method to skip this validation.");
if (cloudEvent.Id == null)
throw new ArgumentException("The Id property must be specified in each CloudEvent. " + Environment.NewLine + "The `skipValidation` parameter can be set to 'true' in the CloudEvent.Parse or CloudEvent.ParseEvents method to skip this validation.");
if (cloudEvent.SpecVersion != "1.0") {
if (cloudEvent.SpecVersion == null)
throw new ArgumentException("The specverion was not set in at least one of the events in the payload. This type only supports specversion '1.0', which must be set for each event. " + Environment.NewLine + "The `skipValidation` parameter can be set to 'true' in the CloudEvent.Parse or CloudEvent.ParseEvents method to skip this validation." + Environment.NewLine + element.ToString(), "element");
throw new ArgumentException("The specverion value of '" + cloudEvent.SpecVersion + "' is not supported by CloudEvent. This type only supports specversion '1.0'. " + Environment.NewLine + "The `skipValidation` parameter can be set to 'true' in the CloudEvent.Parse or CloudEvent.ParseEvents method to skip this validation." + Environment.NewLine + element.ToString(), "element");
}
}
return cloudEvent;
}
public override void Write(Utf8JsonWriter writer, CloudEvent value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("id");
writer.WriteStringValue(value.Id);
writer.WritePropertyName("source");
writer.WriteStringValue(value.Source);
writer.WritePropertyName("type");
writer.WriteStringValue(value.Type);
if ((object)value.Data != null) {
switch (value.DataFormat) {
case CloudEventDataFormat.Binary:
writer.WritePropertyName("data_base64");
writer.WriteBase64StringValue(value.Data.ToArray());
break;
case CloudEventDataFormat.Json:
using (JsonDocument jsonDocument = JsonDocument.Parse(value.Data.ToMemory(), default(JsonDocumentOptions))) {
writer.WritePropertyName("data");
jsonDocument.RootElement.WriteTo(writer);
}
break;
}
}
if (value.Time.HasValue) {
writer.WritePropertyName("time");
writer.WriteStringValue(value.Time.Value);
}
writer.WritePropertyName("specversion");
writer.WriteStringValue(value.SpecVersion);
if (value.DataSchema != null) {
writer.WritePropertyName("dataschema");
writer.WriteStringValue(value.DataSchema);
}
if (value.DataContentType != null) {
writer.WritePropertyName("datacontenttype");
writer.WriteStringValue(value.DataContentType);
}
if (value.Subject != null) {
writer.WritePropertyName("subject");
writer.WriteStringValue(value.Subject);
}
foreach (KeyValuePair<string, object> extensionAttribute in value.ExtensionAttributes) {
writer.WritePropertyName(extensionAttribute.Key);
WriteObjectValue(writer, extensionAttribute.Value);
}
writer.WriteEndObject();
}
private static void WriteObjectValue(Utf8JsonWriter writer, [System.Runtime.CompilerServices.Nullable(2)] object value)
{
if (value != null) {
byte[] array = value as byte[];
if (array == null) {
if (!(value is ReadOnlyMemory<byte>)) {
if (value is int) {
int value2 = (int)value;
writer.WriteNumberValue(value2);
} else {
string text = value as string;
if (text == null) {
if (value is bool) {
bool value3 = (bool)value;
writer.WriteBooleanValue(value3);
} else if (value is Guid) {
Guid value4 = (Guid)value;
writer.WriteStringValue(value4);
} else {
Uri uri = value as Uri;
if ((object)uri == null) {
if (value is DateTimeOffset) {
DateTimeOffset value5 = (DateTimeOffset)value;
writer.WriteStringValue(value5);
} else if (value is DateTime) {
DateTime value6 = (DateTime)value;
writer.WriteStringValue(value6);
} else {
IEnumerable<KeyValuePair<string, object>> enumerable = value as IEnumerable<KeyValuePair<string, object>>;
if (enumerable == null) {
IEnumerable<object> enumerable2 = value as IEnumerable<object>;
if (enumerable2 == null)
throw new NotSupportedException("Not supported type " + value.GetType()?.ToString());
writer.WriteStartArray();
foreach (object item in enumerable2) {
WriteObjectValue(writer, item);
}
writer.WriteEndArray();
} else {
writer.WriteStartObject();
foreach (KeyValuePair<string, object> item2 in enumerable) {
writer.WritePropertyName(item2.Key);
WriteObjectValue(writer, item2.Value);
}
writer.WriteEndObject();
}
}
} else
writer.WriteStringValue(uri.ToString());
}
} else
writer.WriteStringValue(text);
}
} else
writer.WriteStringValue(Convert.ToBase64String(((ReadOnlyMemory<byte>)value).ToArray()));
} else
writer.WriteStringValue(Convert.ToBase64String(array));
} else
writer.WriteNullValue();
}
[System.Runtime.CompilerServices.NullableContext(2)]
private static object GetObject([In] [System.Runtime.CompilerServices.IsReadOnly] ref JsonElement element)
{
switch (element.ValueKind) {
case JsonValueKind.String:
return element.GetString();
case JsonValueKind.Number:
if (element.TryGetInt32(out int value))
return value;
if (element.TryGetInt64(out long value2))
return value2;
return element.GetDouble();
case JsonValueKind.True:
return true;
case JsonValueKind.False:
return false;
case JsonValueKind.Undefined:
case JsonValueKind.Null:
return null;
case JsonValueKind.Object: {
Dictionary<string, object> dictionary = new Dictionary<string, object>();
{
foreach (JsonProperty item in element.EnumerateObject()) {
Dictionary<string, object> dictionary2 = dictionary;
string name = item.Name;
JsonElement element3 = item.Value;
dictionary2.Add(name, GetObject(ref element3));
}
return dictionary;
}
}
case JsonValueKind.Array: {
List<object> list = new List<object>();
foreach (JsonElement item2 in element.EnumerateArray()) {
JsonElement element2 = item2;
list.Add(GetObject(ref element2));
}
return list.ToArray();
}
default:
throw new NotSupportedException("Not supported value kind " + element.ValueKind.ToString());
}
}
}
}