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());
            }
        }
    }
}