/// <summary>
        /// Converts this listener request into a CloudEvent object, with the given extensions,
        /// overriding the formatter.
        /// </summary>
        /// <param name="httpListenerRequest">Listener request</param>
        /// <param name="formatter"></param>
        /// <param name="extensions">List of extension instances</param>
        /// <returns>A CloudEvent instance or 'null' if the response message doesn't hold a CloudEvent</returns>
        public static CloudEvent ToCloudEvent(this HttpListenerRequest httpListenerRequest,
                                              ICloudEventFormatter formatter = null,
                                              params ICloudEventExtension[] extensions)
        {
            if (httpListenerRequest.ContentType != null &&
                httpListenerRequest.ContentType.StartsWith(CloudEvent.MediaType,
                                                           StringComparison.InvariantCultureIgnoreCase))
            {
                // handle structured mode
                if (formatter == null)
                {
                    // if we didn't get a formatter, pick one
                    if (httpListenerRequest.ContentType.EndsWith(JsonEventFormatter.MediaTypeSuffix,
                                                                 StringComparison.InvariantCultureIgnoreCase))
                    {
                        formatter = jsonFormatter;
                    }
                    else
                    {
                        throw new InvalidOperationException("Unsupported CloudEvents encoding");
                    }
                }

                return(formatter.DecodeStructuredEvent(httpListenerRequest.InputStream, extensions));
            }
            else
            {
                CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
                if (httpListenerRequest.Headers[SpecVersionHttpHeader1] != null)
                {
                    version = CloudEventsSpecVersion.V0_1;
                }

                if (httpListenerRequest.Headers[SpecVersionHttpHeader2] != null)
                {
                    version = httpListenerRequest.Headers[SpecVersionHttpHeader2] == "0.2"
                        ? CloudEventsSpecVersion.V0_2 : httpListenerRequest.Headers[SpecVersionHttpHeader2] == "0.3"
                            ? CloudEventsSpecVersion.V0_3 : CloudEventsSpecVersion.Default;
                }

                var cloudEvent = new CloudEvent(version, extensions);
                var attributes = cloudEvent.GetAttributes();
                foreach (var httpRequestHeaders in httpListenerRequest.Headers.AllKeys)
                {
                    if (httpRequestHeaders.Equals(SpecVersionHttpHeader1,
                                                  StringComparison.InvariantCultureIgnoreCase) ||
                        httpRequestHeaders.Equals(SpecVersionHttpHeader2, StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    if (httpRequestHeaders.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase))
                    {
                        string headerValue = httpListenerRequest.Headers[httpRequestHeaders];
                        if (headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
                            headerValue.StartsWith("[") && headerValue.EndsWith("]"))
                        {
                            attributes[httpRequestHeaders.Substring(3)] =
                                JsonConvert.DeserializeObject(headerValue);
                        }
                        else
                        {
                            attributes[httpRequestHeaders.Substring(3)] = headerValue;
                            attributes[httpRequestHeaders.Substring(3)] = headerValue;
                        }
                    }
                }

                cloudEvent.DataContentType = httpListenerRequest.ContentType != null
                    ? new ContentType(httpListenerRequest.ContentType)
                    : null;
                cloudEvent.Data = httpListenerRequest.InputStream;
                return(cloudEvent);
            }
        }
示例#2
0
        public async Task SetsTraceParentExtension(bool inclTraceparent, bool inclTracestate)
        {
            var mockTransport = new MockTransport(new MockResponse(200));
            var options       = new EventGridPublisherClientOptions
            {
                Transport = mockTransport
            };
            EventGridPublisherClient client =
                new EventGridPublisherClient(
                    new Uri("http://localHost"),
                    new AzureKeyCredential("fakeKey"),
                    options);
            var activity = new Activity($"{nameof(EventGridPublisherClient)}.{nameof(EventGridPublisherClient.SendEvents)}");

            activity.SetW3CFormat();
            activity.Start();
            List <CloudEvent> inputEvents = new List <CloudEvent>();

            for (int i = 0; i < 10; i++)
            {
                var cloudEvent =
                    new CloudEvent
                {
                    Subject = "record",
                    Source  = new Uri("http://localHost"),
                    Id      = Guid.NewGuid().ToString(),
                    Time    = DateTime.Now,
                    Type    = "test"
                };

                if (inclTraceparent && inclTracestate && i % 2 == 0)
                {
                    cloudEvent.SetAttributeFromString("traceparent", "traceparentValue");
                }
                if (inclTracestate && i % 2 == 0)
                {
                    cloudEvent.SetAttributeFromString("tracestate", "param:value");
                }
                inputEvents.Add(cloudEvent);
            }
            await client.SendCloudNativeCloudEventsAsync(inputEvents);

            activity.Stop();
            List <CloudEvent>        endEvents = DeserializeRequest(mockTransport.SingleRequest);
            IEnumerator <CloudEvent> inputEnum = inputEvents.GetEnumerator();

            foreach (CloudEvent cloudEvent in endEvents)
            {
                inputEnum.MoveNext();
                var inputAttributes = inputEnum.Current.GetPopulatedAttributes().Select(pair => pair.Key.Name).ToList();
                if (inputAttributes.Contains(TraceParentHeaderName) &&
                    inputAttributes.Contains(TraceStateHeaderName))
                {
                    Assert.AreEqual(
                        inputEnum.Current[TraceParentHeaderName],
                        cloudEvent[TraceParentHeaderName]);

                    Assert.AreEqual(
                        inputEnum.Current[TraceStateHeaderName],
                        cloudEvent[TraceStateHeaderName]);
                }
                else if (inputAttributes.Contains(TraceParentHeaderName))
                {
                    Assert.AreEqual(
                        inputEnum.Current[TraceParentHeaderName],
                        cloudEvent[TraceParentHeaderName]);
                }
                else if (inputAttributes.Contains(TraceStateHeaderName))
                {
                    Assert.AreEqual(
                        inputEnum.Current[TraceStateHeaderName],
                        cloudEvent[TraceStateHeaderName]);
                }
                else
                {
                    Assert.AreEqual(
                        activity.Id,
                        cloudEvent[TraceParentHeaderName]);
                }
            }
        }
示例#3
0
 /// <summary> Publishes a set of CloudEvents to an Event Grid topic. </summary>
 /// <param name="client">The <see cref="EventGridPublisherClient"/> instance to extend.</param>
 /// <param name="cloudEvent"> The event to be published to Event Grid. </param>
 /// <param name="cancellationToken"> An optional cancellation token instance to signal the request to cancel the operation.</param>
 public static async Task <Response> SendCloudNativeCloudEventAsync(
     this EventGridPublisherClient client,
     CloudEvent cloudEvent,
     CancellationToken cancellationToken = default) =>
 await SendCloudNativeCloudEventsAsync(client, new CloudEvent[] { cloudEvent }, cancellationToken).ConfigureAwait(false);
 public override void DecodeBinaryModeEventData(byte[] value, CloudEvent cloudEvent) =>
 throw new NotSupportedException("The Avro event formatter does not support binary content mode");
        /// <summary>
        /// Converts this HTTP request into a CloudEvent object, with the given extensions,
        /// overriding the formatter.
        /// </summary>
        /// <param name="httpRequest">HTTP request</param>
        /// <param name="formatter"></param>
        /// <param name="extensions">List of extension instances</param>
        /// <returns>A CloudEvent instance or 'null' if the request message doesn't hold a CloudEvent</returns>
        public static async ValueTask <CloudEvent> ReadCloudEventAsync(this HttpRequest httpRequest,
                                                                       ICloudEventFormatter formatter = null,
                                                                       params ICloudEventExtension[] extensions)
        {
            if (httpRequest.ContentType != null &&
                httpRequest.ContentType.StartsWith(CloudEvent.MediaType,
                                                   StringComparison.InvariantCultureIgnoreCase))
            {
                // handle structured mode
                if (formatter == null)
                {
                    // if we didn't get a formatter, pick one
                    var contentType = httpRequest.ContentType.Split(';')[0].Trim();
                    if (contentType.EndsWith(JsonEventFormatter.MediaTypeSuffix,
                                             StringComparison.InvariantCultureIgnoreCase))
                    {
                        formatter = jsonFormatter;
                    }
                    else
                    {
                        throw new InvalidOperationException("Unsupported CloudEvents encoding");
                    }
                }

                return(await formatter.DecodeStructuredEventAsync(httpRequest.Body, extensions));
            }
            else
            {
                CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
                if (httpRequest.Headers[SpecVersionHttpHeader1] != StringValues.Empty)
                {
                    version = CloudEventsSpecVersion.V0_1;
                }

                if (httpRequest.Headers[SpecVersionHttpHeader2] != StringValues.Empty)
                {
                    switch (httpRequest.Headers[SpecVersionHttpHeader2])
                    {
                    case "0.2":
                        version = CloudEventsSpecVersion.V0_2;
                        break;

                    case "0.3":
                        version = CloudEventsSpecVersion.V0_3;
                        break;

                    default:
                        version = CloudEventsSpecVersion.Default;
                        break;
                    }
                }

                var cloudEvent = new CloudEvent(version, extensions);
                var attributes = cloudEvent.GetAttributes();
                foreach (var httpRequestHeader in httpRequest.Headers.Keys)
                {
                    if (httpRequestHeader.Equals(SpecVersionHttpHeader1,
                                                 StringComparison.InvariantCultureIgnoreCase) ||
                        httpRequestHeader.Equals(SpecVersionHttpHeader2, StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    if (httpRequestHeader.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase))
                    {
                        string headerValue = WebUtility.UrlDecode(httpRequest.Headers[httpRequestHeader]);
                        // maps in headers have been abolished in 1.0
                        if (version != CloudEventsSpecVersion.V1_0 &&
                            headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
                            headerValue.StartsWith("[") && headerValue.EndsWith("]"))
                        {
                            attributes[httpRequestHeader.Substring(3)] =
                                JsonConvert.DeserializeObject(headerValue);
                        }
                        else
                        {
                            attributes[httpRequestHeader.Substring(3)] = headerValue;
                        }
                    }
                }

                cloudEvent.DataContentType = httpRequest.ContentType != null
                    ? new ContentType(httpRequest.ContentType)
                    : null;
                cloudEvent.Data = await new StreamReader(httpRequest.Body, Encoding.UTF8).ReadToEndAsync();
                return(cloudEvent);
            }
        }
示例#6
0
 /// <summary> Publishes a set of CloudEvents to an Event Grid topic. </summary>
 /// <param name="client">The <see cref="EventGridPublisherClient"/> instance to extend.</param>
 /// <param name="cloudEvent"> The event to be published to Event Grid. </param>
 /// <param name="cancellationToken"> An optional cancellation token instance to signal the request to cancel the operation.</param>
 public static Response SendCloudNativeCloudEvent(
     this EventGridPublisherClient client,
     CloudEvent cloudEvent,
     CancellationToken cancellationToken = default) =>
 SendCloudNativeCloudEvents(client, new CloudEvent[] { cloudEvent }, cancellationToken);
 /// <summary>
 /// Encodes a CloudEvent as the body of a structured-mode message.
 /// </summary>
 /// <param name="cloudEvent">The CloudEvent to encode. Must not be null.</param>
 /// <param name="contentType">On successful return, the content type of the structured-mode data.
 /// Must not be null (on return).</param>
 /// <returns>The structured-mode representation of the CloudEvent.</returns>
 public abstract byte[] EncodeStructuredModeMessage(CloudEvent cloudEvent, out ContentType contentType);
示例#8
0
        static CloudEvent ToCloudEventInternal(HttpResponseMessage httpResponseMessage,
                                               ICloudEventFormatter formatter, ICloudEventExtension[] extensions)
        {
            if (httpResponseMessage.Content?.Headers.ContentType != null &&
                httpResponseMessage.Content.Headers.ContentType.MediaType.StartsWith("application/cloudevents",
                                                                                     StringComparison.InvariantCultureIgnoreCase))
            {
                // handle structured mode
                if (formatter == null)
                {
                    // if we didn't get a formatter, pick one
                    if (httpResponseMessage.Content.Headers.ContentType.MediaType.EndsWith("+json",
                                                                                           StringComparison.InvariantCultureIgnoreCase))
                    {
                        formatter = jsonFormatter;
                    }
                    else
                    {
                        throw new InvalidOperationException("Unsupported CloudEvents encoding");
                    }
                }

                return(formatter.DecodeStructuredEvent(
                           httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(),
                           extensions));
            }
            else
            {
                CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
                if (httpResponseMessage.Headers.Contains(SpecVersionHttpHeader1))
                {
                    version = CloudEventsSpecVersion.V0_1;
                }

                if (httpResponseMessage.Headers.Contains(SpecVersionHttpHeader2))
                {
                    version = httpResponseMessage.Headers.GetValues(SpecVersionHttpHeader2).First() == "0.2"
                        ? CloudEventsSpecVersion.V0_2 : httpResponseMessage.Headers.GetValues(SpecVersionHttpHeader2).First() == "0.3"
                            ? CloudEventsSpecVersion.V0_3 : CloudEventsSpecVersion.Default;
                }

                var cloudEvent = new CloudEvent(version, extensions);
                var attributes = cloudEvent.GetAttributes();
                foreach (var httpResponseHeader in httpResponseMessage.Headers)
                {
                    if (httpResponseHeader.Key.Equals(SpecVersionHttpHeader1,
                                                      StringComparison.InvariantCultureIgnoreCase) ||
                        httpResponseHeader.Key.Equals(SpecVersionHttpHeader2,
                                                      StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    if (httpResponseHeader.Key.StartsWith(HttpHeaderPrefix,
                                                          StringComparison.InvariantCultureIgnoreCase))
                    {
                        string headerValue = httpResponseHeader.Value.First();
                        var    name        = httpResponseHeader.Key.Substring(3);

                        // abolished structures in headers in 1.0
                        if (version != CloudEventsSpecVersion.V1_0 && (headerValue.StartsWith("\"") && headerValue.EndsWith("\"") ||
                                                                       headerValue.StartsWith("'") && headerValue.EndsWith("'") ||
                                                                       headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
                                                                       headerValue.StartsWith("[") && headerValue.EndsWith("]")))
                        {
                            attributes[name] = jsonFormatter.DecodeAttribute(version, name,
                                                                             Encoding.UTF8.GetBytes(headerValue), extensions);
                        }
                        else
                        {
                            attributes[name] = headerValue;
                        }
                    }
                }

                cloudEvent.DataContentType = httpResponseMessage.Content?.Headers.ContentType != null
                    ? new ContentType(httpResponseMessage.Content.Headers.ContentType.ToString())
                    : null;
                cloudEvent.Data = httpResponseMessage.Content?.ReadAsStreamAsync().GetAwaiter().GetResult();
                return(cloudEvent);
            }
        }
 /// <summary>
 /// Encodes the data from <paramref name="cloudEvent"/> in a manner suitable for a binary mode message.
 /// </summary>
 /// <exception cref="ArgumentException">The data in the given CloudEvent cannot be encoded by this
 /// event formatter.</exception>
 /// <returns>The binary-mode representation of the CloudEvent.</returns>
 public abstract byte[] EncodeBinaryModeEventData(CloudEvent cloudEvent);
示例#10
0
 /// <summary>
 /// Decodes the given data obtained from a binary-mode message, populating the <see cref="CloudEvent.Data"/>
 /// property of <paramref name="cloudEvent"/>. Other attributes within the CloudEvent may be used to inform
 /// the interpretation of the data. This method is expected to be called after all other aspects of the CloudEvent
 /// have been populated.
 /// </summary>
 /// <param name="data">The data from the message. Must not be null, but may be empty.</param>
 /// <param name="cloudEvent">The CloudEvent whose Data property should be populated. Must not be null.</param>
 /// <exception cref="ArgumentException">The data in the given CloudEvent cannot be decoded by this
 /// event formatter.</exception>
 public abstract void DecodeBinaryModeEventData(byte[] data, CloudEvent cloudEvent);
 /// <summary>
 /// Encodes a CloudEvent as the body of a structured-mode message.
 /// </summary>
 /// <param name="cloudEvent">The CloudEvent to encode. Must not be null.</param>
 /// <param name="contentType">On successful return, the content type of the structured-mode message body.
 /// Must not be null (on return).</param>
 /// <returns>The structured-mode representation of the CloudEvent.</returns>
 public abstract ReadOnlyMemory <byte> EncodeStructuredModeMessage(CloudEvent cloudEvent, out ContentType contentType);
 /// <summary>
 /// Encodes the data from <paramref name="cloudEvent"/> in a manner suitable for a binary mode message.
 /// </summary>
 /// <exception cref="ArgumentException">The data in the given CloudEvent cannot be encoded by this
 /// event formatter.</exception>
 /// <returns>The binary-mode representation of the CloudEvent.</returns>
 public abstract ReadOnlyMemory <byte> EncodeBinaryModeEventData(CloudEvent cloudEvent);
 /// <summary>
 /// Decodes the given data obtained from a binary-mode message, populating the <see cref="CloudEvent.Data"/>
 /// property of <paramref name="cloudEvent"/>. Other attributes within the CloudEvent may be used to inform
 /// the interpretation of the message body. This method is expected to be called after all other aspects of the CloudEvent
 /// have been populated.
 /// </summary>
 /// <param name="body">The message body (content). Must not be null, but may be empty.</param>
 /// <param name="cloudEvent">The CloudEvent whose Data property should be populated. Must not be null.</param>
 /// <exception cref="ArgumentException">The data in the given CloudEvent cannot be decoded by this
 /// event formatter.</exception>
 public abstract void DecodeBinaryModeEventData(ReadOnlyMemory <byte> body, CloudEvent cloudEvent);
示例#14
0
        /// <summary>
        /// Copies the CloudEvent into this HttpListenerResponse instance
        /// </summary>
        /// <param name="httpListenerResponse">this</param>
        /// <param name="cloudEvent">CloudEvent to copy</param>
        /// <param name="contentMode">Content mode (structured or binary)</param>
        /// <param name="formatter">Formatter</param>
        /// <returns>Task</returns>
        public static Task CopyFromAsync(this HttpListenerResponse httpListenerResponse, CloudEvent cloudEvent,
                                         ContentMode contentMode, ICloudEventFormatter formatter)
        {
            if (contentMode == ContentMode.Structured)
            {
                var buffer =
                    formatter.EncodeStructuredEvent(cloudEvent, out var contentType);
                httpListenerResponse.ContentType = contentType.ToString();
                MapAttributesToListenerResponse(cloudEvent, httpListenerResponse);
                return(httpListenerResponse.OutputStream.WriteAsync(buffer, 0, buffer.Length));
            }

            Stream stream = MapDataAttributeToStream(cloudEvent, formatter);

            httpListenerResponse.ContentType = cloudEvent.DataContentType.ToString();
            MapAttributesToListenerResponse(cloudEvent, httpListenerResponse);
            return(stream.CopyToAsync(httpListenerResponse.OutputStream));
        }
示例#15
0
 /// <inheritdoc />
 public override void DecodeBinaryModeEventData(ReadOnlyMemory <byte> body, CloudEvent cloudEvent) =>
 throw new NotSupportedException("The Avro event formatter does not support binary content mode");
示例#16
0
        /// <summary>
        /// Converts this listener request into a CloudEvent object, with the given extensions,
        /// overriding the formatter.
        /// </summary>
        /// <param name="httpListenerRequest">Listener request</param>
        /// <param name="formatter"></param>
        /// <param name="extensions">List of extension instances</param>
        /// <returns>A CloudEvent instance or 'null' if the request message doesn't hold a CloudEvent</returns>
        public static CloudEvent ToCloudEvent(this HttpRequestMessage httpListenerRequest,
                                              ICloudEventFormatter formatter = null,
                                              params ICloudEventExtension[] extensions)
        {
            if (httpListenerRequest.Content != null && httpListenerRequest.Content.Headers.ContentType != null &&
                httpListenerRequest.Content.Headers.ContentType.MediaType.StartsWith(CloudEvent.MediaType,
                                                                                     StringComparison.InvariantCultureIgnoreCase))
            {
                // handle structured mode
                if (formatter == null)
                {
                    // if we didn't get a formatter, pick one
                    if (httpListenerRequest.Content.Headers.ContentType.MediaType.EndsWith(
                            JsonEventFormatter.MediaTypeSuffix,
                            StringComparison.InvariantCultureIgnoreCase))
                    {
                        formatter = jsonFormatter;
                    }
                    else
                    {
                        throw new InvalidOperationException("Unsupported CloudEvents encoding");
                    }
                }

                return(formatter.DecodeStructuredEvent(
                           httpListenerRequest.Content.ReadAsStreamAsync().GetAwaiter().GetResult(), extensions));
            }
            else
            {
                CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
                if (httpListenerRequest.Headers.Contains(SpecVersionHttpHeader1))
                {
                    version = CloudEventsSpecVersion.V0_1;
                }

                if (httpListenerRequest.Headers.Contains(SpecVersionHttpHeader2))
                {
                    version = httpListenerRequest.Headers.GetValues(SpecVersionHttpHeader2).First() == "0.2"
                        ? CloudEventsSpecVersion.V0_2
                        : CloudEventsSpecVersion.Default;
                }

                var cloudEvent = new CloudEvent(version, extensions);
                var attributes = cloudEvent.GetAttributes();
                foreach (var httpRequestHeaders in httpListenerRequest.Headers)
                {
                    if (httpRequestHeaders.Key.Equals(SpecVersionHttpHeader1,
                                                      StringComparison.InvariantCultureIgnoreCase) ||
                        httpRequestHeaders.Key.Equals(SpecVersionHttpHeader2,
                                                      StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    if (httpRequestHeaders.Key.StartsWith(HttpHeaderPrefix,
                                                          StringComparison.InvariantCultureIgnoreCase))
                    {
                        string headerValue = httpListenerRequest.Headers.GetValues(httpRequestHeaders.Key).First();
                        // maps in headers have been abolished in version 1.0
                        if (version != CloudEventsSpecVersion.V1_0 &&
                            (headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
                             headerValue.StartsWith("[") && headerValue.EndsWith("]")))
                        {
                            attributes[httpRequestHeaders.Key.Substring(3)] =
                                JsonConvert.DeserializeObject(headerValue);
                        }
                        else
                        {
                            attributes[httpRequestHeaders.Key.Substring(3)] = headerValue;
                        }
                    }
                }

                cloudEvent.DataContentType = httpListenerRequest.Content?.Headers.ContentType != null
                    ? new ContentType(httpListenerRequest.Content.Headers.ContentType.MediaType)
                    : null;
                cloudEvent.Data = httpListenerRequest.Content?.ReadAsStreamAsync().GetAwaiter().GetResult();
                return(cloudEvent);
            }
        }
示例#17
0
        public CloudEvent DecodeJObject(JObject jObject, IEnumerable <ICloudEventExtension> extensions = null)
        {
            CloudEventsSpecVersion specVersion = CloudEventsSpecVersion.Default;

            if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1)) ||
                jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1).ToLowerInvariant()))
            {
                specVersion = CloudEventsSpecVersion.V0_1;
            }
            if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)) ||
                jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2).ToLowerInvariant()))
            {
                specVersion =
                    ((string)jObject[CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)] ==
                     "0.2")
                        ? CloudEventsSpecVersion.V0_2 :
                    ((string)jObject[CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_3)] ==
                     "0.3")
                            ? CloudEventsSpecVersion.V0_3 : CloudEventsSpecVersion.Default;
            }

            var cloudEvent = new CloudEvent(specVersion, extensions);
            var attributes = cloudEvent.GetAttributes();

            foreach (var keyValuePair in jObject)
            {
                // skip the version since we set that above
                if (keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), StringComparison.InvariantCultureIgnoreCase) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), StringComparison.InvariantCultureIgnoreCase) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V1_0), StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }

                if (specVersion == CloudEventsSpecVersion.V1_0)
                {
                    // handle base64 encoded binaries
                    if (keyValuePair.Key.Equals("data_base64"))
                    {
                        attributes["data"] = Convert.FromBase64String(keyValuePair.Value.ToString());
                        continue;
                    }
                }

                switch (keyValuePair.Value.Type)
                {
                case JTokenType.String:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <string>();
                    break;

                case JTokenType.Date:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <DateTime>();
                    break;

                case JTokenType.Uri:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <Uri>();
                    break;

                case JTokenType.Null:
                    attributes[keyValuePair.Key] = null;
                    break;

                case JTokenType.Integer:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <int>();
                    break;

                default:
                    attributes[keyValuePair.Key] = (dynamic)keyValuePair.Value;
                    break;
                }
            }

            return(cloudEvent);
        }
        public async Task SetsTraceParentExtension(bool inclTraceparent, bool inclTracestate)
        {
            var mockTransport = new MockTransport(new MockResponse(200));
            var options       = new EventGridPublisherClientOptions
            {
                Transport = mockTransport
            };
            EventGridPublisherClient client =
                new EventGridPublisherClient(
                    new Uri("http://localHost"),
                    new AzureKeyCredential("fakeKey"),
                    options);
            var activity = new Activity($"{nameof(EventGridPublisherClient)}.{nameof(EventGridPublisherClient.SendEvents)}");

            activity.SetW3CFormat();
            activity.Start();
            List <CloudEvent> eventsList = new List <CloudEvent>();

            for (int i = 0; i < 10; i++)
            {
                var cloudEvent =
                    new CloudEvent(
                        "record",
                        new Uri("http://localHost"),
                        Guid.NewGuid().ToString(),
                        DateTime.Now);

                if (inclTraceparent && inclTracestate && i % 2 == 0)
                {
                    cloudEvent.GetAttributes().Add("traceparent", "traceparentValue");
                }
                if (inclTracestate && i % 2 == 0)
                {
                    cloudEvent.GetAttributes().Add("tracestate", "param:value");
                }
                eventsList.Add(cloudEvent);
            }
            await client.SendCloudEventsAsync(eventsList);

            activity.Stop();
            List <CloudEvent>        cloudEvents = DeserializeRequest(mockTransport.SingleRequest);
            IEnumerator <CloudEvent> cloudEnum   = eventsList.GetEnumerator();

            foreach (CloudEvent cloudEvent in cloudEvents)
            {
                cloudEnum.MoveNext();
                IDictionary <string, object> cloudEventAttr = cloudEnum.Current.GetAttributes();
                if (cloudEventAttr.ContainsKey(TraceParentHeaderName) &&
                    cloudEventAttr.ContainsKey(TraceStateHeaderName))
                {
                    Assert.AreEqual(
                        cloudEventAttr[TraceParentHeaderName],
                        cloudEvent.GetAttributes()[TraceParentHeaderName]);

                    Assert.AreEqual(
                        cloudEventAttr[TraceStateHeaderName],
                        cloudEvent.GetAttributes()[TraceStateHeaderName]);
                }
                else if (cloudEventAttr.ContainsKey(TraceParentHeaderName))
                {
                    Assert.AreEqual(
                        cloudEventAttr[TraceParentHeaderName],
                        cloudEvent.GetAttributes()[TraceParentHeaderName]);
                }
                else if (cloudEventAttr.ContainsKey(TraceStateHeaderName))
                {
                    Assert.AreEqual(
                        cloudEventAttr[TraceStateHeaderName],
                        cloudEvent.GetAttributes()[TraceStateHeaderName]);
                }
                else
                {
                    Assert.AreEqual(
                        activity.Id,
                        cloudEvent.GetAttributes()[TraceParentHeaderName]);
                }
            }
        }
        public CloudEvent DecodeJObject(JObject jObject, IEnumerable <ICloudEventExtension> extensions = null)
        {
            CloudEventsSpecVersion specVersion = CloudEventsSpecVersion.Default;

            if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1)) ||
                jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1).ToLowerInvariant()))
            {
                specVersion = CloudEventsSpecVersion.V0_1;
            }
            if (jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)) ||
                jObject.ContainsKey(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2).ToLowerInvariant()))
            {
                specVersion =
                    ((string)jObject[CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)] ==
                     "0.2")
                        ? CloudEventsSpecVersion.V0_2 :
                    ((string)jObject[CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_3)] ==
                     "0.3")
                            ? CloudEventsSpecVersion.V0_3 : CloudEventsSpecVersion.Default;
            }

            var cloudEvent = new CloudEvent(specVersion, extensions);
            var attributes = cloudEvent.GetAttributes();

            foreach (var keyValuePair in jObject)
            {
                if (keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1)) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2)) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_3)))
                {
                    continue;
                }

                switch (keyValuePair.Value.Type)
                {
                case JTokenType.String:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <string>();
                    break;

                case JTokenType.Date:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <DateTime>();
                    break;

                case JTokenType.Uri:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <Uri>();
                    break;

                case JTokenType.Null:
                    attributes[keyValuePair.Key] = null;
                    break;

                case JTokenType.Integer:
                    attributes[keyValuePair.Key] = keyValuePair.Value.ToObject <int>();
                    break;

                default:
                    attributes[keyValuePair.Key] = (dynamic)keyValuePair.Value;
                    break;
                }
            }

            return(cloudEvent);
        }