< Summary

Class:Microsoft.Azure.EventGrid.EventGridSubscriber
Assembly:Microsoft.Azure.EventGrid
File(s):C:\Git\azure-sdk-for-net\sdk\eventgrid\Microsoft.Azure.EventGrid\src\Customization\EventGridSubscriber.cs
Covered lines:65
Uncovered lines:2
Coverable lines:67
Total lines:240
Line coverage:97% (65 of 67)
Covered branches:18
Total branches:20
Branch coverage:90% (18 of 20)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
.ctor()-100%100%
DeserializeEventGridEvents(...)-100%100%
DeserializeEventGridEvents(...)-100%100%
DeserializeEventGridEvents(...)-100%100%
DeserializeEventGridEvents(...)-100%100%
AddOrUpdateCustomEventMapping(...)-87.5%50%
TryGetCustomEventMapping(...)-100%100%
ListAllCustomEventMappings()-100%100%
TryRemoveCustomEventMapping(...)-100%100%
ValidateEventType(...)-66.67%50%
DeserializeEventGridEventData(...)-100%100%
GetJsonSerializerWithPolymorphicSupport()-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\eventgrid\Microsoft.Azure.EventGrid\src\Customization\EventGridSubscriber.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License. See License.txt in the project root for
 3// license information.
 4
 5using Microsoft.Azure.EventGrid.Models;
 6using Microsoft.Rest.Serialization;
 7using Newtonsoft.Json;
 8using Newtonsoft.Json.Linq;
 9using System;
 10using System.Collections.Concurrent;
 11using System.Collections.Generic;
 12using System.IO;
 13
 14namespace Microsoft.Azure.EventGrid
 15{
 16    public class EventGridSubscriber : IEventGridEventDeserializer, ICustomEventTypeMapper
 17    {
 18        static readonly JsonSerializer defaultJsonSerializer;
 19        readonly ConcurrentDictionary<string, Type> customEventTypeMapping;
 20
 21        static EventGridSubscriber()
 22        {
 123            defaultJsonSerializer = GetJsonSerializerWithPolymorphicSupport();
 124        }
 25
 9326        public EventGridSubscriber()
 27        {
 9328            customEventTypeMapping = new ConcurrentDictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
 9329        }
 30
 31        /// <summary>
 32        /// Deserializes the provided event data using a default JSON serializer that supports all system event types.
 33        /// A webhook/function that is consuming events can call this function to deserialize EventGrid events.
 34        /// For system events, the Data property of each event in the returned array will be set to the appropriate
 35        /// type (e.g. StorageBlobCreatedEventData). For events on custom topics where the type of the Data property
 36        /// can be of any type, the calling function will have to first add a custom event mapping before calling this f
 37        /// </summary>
 38        /// <param name="requestContent">The JSON string containing an array of EventGrid events</param>
 39        /// <returns>A list of EventGrid Events</returns>
 40        public EventGridEvent[] DeserializeEventGridEvents(string requestContent)
 41        {
 8242            return this.DeserializeEventGridEvents(requestContent, defaultJsonSerializer);
 43        }
 44
 45        /// <summary>
 46        /// Deserializes the provided event data using a custom JSON serializer.
 47        /// A webhook/function that is consuming events can call this function to deserialize EventGrid events.
 48        /// For system events, the Data property of each event in the returned array will be set to the appropriate
 49        /// type (e.g. StorageBlobCreatedEventData). For events on custom topics where the type of the Data property
 50        /// can be of any type, the calling function will have to first add a custom event mapping before calling this f
 51        /// </summary>
 52        /// <param name="requestContent">The JSON string containing an array of EventGrid events</param>
 53        /// <param name="jsonSerializer">JsonSerializer to use for the deserialization.</param>
 54        /// <returns>A list of EventGrid Events</returns>
 55        public EventGridEvent[] DeserializeEventGridEvents(string requestContent, JsonSerializer jsonSerializer)
 56        {
 8357            EventGridEvent[] eventGridEvents = JsonConvert.DeserializeObject<EventGridEvent[]>(requestContent, jsonSeria
 8358            return DeserializeEventGridEventData(eventGridEvents, jsonSerializer);
 59        }
 60
 61        /// <summary>
 62        /// Deserializes the provided stream using a default JSON serializer that supports all system event types.
 63        /// A webhook/function that is consuming events can call this function to deserialize EventGrid events.
 64        /// For system events, the Data property of each event in the returned array will be set to the appropriate
 65        /// type (e.g. StorageBlobCreatedEventData). For events on custom topics where the type of the Data property
 66        /// can be of any type, the calling function will have to first add a custom event mapping before calling this f
 67        /// </summary>
 68        /// <param name="requestStream">Request Stream</param>
 69        /// <returns>A list of EventGrid Events</returns>
 70        public EventGridEvent[] DeserializeEventGridEvents(Stream requestStream)
 71        {
 172            return this.DeserializeEventGridEvents(requestStream, defaultJsonSerializer);
 73        }
 74
 75        /// <summary>
 76        /// Deserializes the provided stream using a custom JSON serializer.
 77        /// A webhook/function that is consuming events can call this function to deserialize EventGrid events.
 78        /// For system events, the Data property of each event in the returned array will be set to the appropriate
 79        /// type (e.g. StorageBlobCreatedEventData). For events on custom topics where the type of the Data property
 80        /// can be of any type, the calling function will have to first add a custom event mapping before calling this f
 81        /// </summary>
 82        /// <param name="requestStream">Request Stream</param>
 83        /// <param name="jsonSerializer">JsonSerializer to use for the deserialization.</param>
 84        /// <returns>A list of EventGrid Events</returns>
 85        public EventGridEvent[] DeserializeEventGridEvents(Stream requestStream, JsonSerializer jsonSerializer)
 86        {
 287            EventGridEvent[] eventGridEvents = null;
 88
 289            using (var streamReader = new StreamReader(requestStream))
 90            {
 291                using (var jsonTextReader = new JsonTextReader(streamReader))
 92                {
 293                    eventGridEvents = (EventGridEvent[])jsonSerializer.Deserialize(jsonTextReader, typeof(EventGridEvent
 294                }
 95            }
 96
 297            return DeserializeEventGridEventData(eventGridEvents, jsonSerializer);
 98        }
 99
 100        /// <summary>
 101        /// Adds or updates a custom event mapping that associates an eventType string with the corresponding type of ev
 102        /// </summary>
 103        /// <param name="eventType">The event type to register, such as "Contoso.Items.ItemReceived"</param>
 104        /// <param name="eventDataType">The type of eventdata corresponding to this eventType, such as typeof(ContosoIte
 105        public void AddOrUpdateCustomEventMapping(string eventType, Type eventDataType)
 106        {
 9107            this.ValidateEventType(eventType);
 108
 9109            if (eventDataType == null)
 110            {
 0111                throw new ArgumentNullException(nameof(eventDataType));
 112            }
 113
 9114            this.customEventTypeMapping.AddOrUpdate(
 9115                eventType,
 9116                eventDataType,
 10117                (_, existingValue) => eventDataType);
 9118        }
 119
 120        /// <summary>
 121        /// Gets information about a custom event mapping.
 122        /// </summary>
 123        /// <param name="eventType">The registered event type, such as "Contoso.Items.ItemReceived"</param>
 124        /// <param name="eventDataType">The type of eventdata corresponding to this eventType, such as typeof(ContosoIte
 125        /// <returns>True if the specified mapping exists.</returns>
 126        public bool TryGetCustomEventMapping(string eventType, out Type eventDataType)
 127        {
 9128            this.ValidateEventType(eventType);
 129
 9130            return this.customEventTypeMapping.TryGetValue(eventType, out eventDataType);
 131        }
 132
 133        /// <summary>
 134        /// List all registered custom event mappings.
 135        /// </summary>
 136        /// <returns>An IEnumerable of mappings</returns>
 137        public IEnumerable<KeyValuePair<string, Type>> ListAllCustomEventMappings()
 138        {
 6139            foreach (KeyValuePair<string, Type> kvp in this.customEventTypeMapping)
 140            {
 2141                yield return kvp;
 142            }
 1143        }
 144
 145        /// <summary>
 146        /// Removes a custom event mapping.
 147        /// </summary>
 148        /// <param name="eventType">The registered event type, such as "Contoso.Items.ItemReceived"</param>
 149        /// <param name="eventDataType">The type of eventdata corresponding to this eventType, such as typeof(ContosoIte
 150        /// <returns>True if the specified mapping was removed successfully.</returns>
 151        public bool TryRemoveCustomEventMapping(string eventType, out Type eventDataType)
 152        {
 1153            this.ValidateEventType(eventType);
 1154            return this.customEventTypeMapping.TryRemove(eventType, out eventDataType);
 155        }
 156
 157        void ValidateEventType(string eventType)
 158        {
 19159            if (string.IsNullOrEmpty(eventType))
 160            {
 0161                throw new ArgumentNullException(nameof(eventType));
 162            }
 19163        }
 164
 165        EventGridEvent[] DeserializeEventGridEventData(EventGridEvent[] eventGridEvents, JsonSerializer jsonSerializer)
 166        {
 350167            foreach (EventGridEvent receivedEvent in eventGridEvents)
 168            {
 90169                Type typeOfEventData = null;
 170
 171                // First, let's attempt to find the mapping for the event type in the system event type mapping.
 172                // Note that system event data would always be of type JObject.
 90173                if (SystemEventTypeMappings.SystemEventMappings.TryGetValue(receivedEvent.EventType, out typeOfEventData
 174                {
 82175                    JObject dataObject = receivedEvent.Data as JObject;
 82176                    if (dataObject != null)
 177                    {
 82178                        var eventData = dataObject.ToObject(typeOfEventData, jsonSerializer);
 82179                        receivedEvent.Data = eventData;
 180                    }
 181                }
 182                // If not a system event, let's attempt to find the mapping for the event type in the custom event mappi
 8183                else if (this.TryGetCustomEventMapping(receivedEvent.EventType, out typeOfEventData))
 184                {
 8185                    JToken dataToken = receivedEvent.Data as JToken;
 8186                    if (dataToken == null)
 187                    {
 188                        // Nothing to do (e.g. this will happen if Data is a primitive/string type).
 189                        continue;
 190                    }
 191
 6192                    switch (dataToken.Type)
 193                    {
 194                        case JTokenType.Object:
 5195                            var eventData = dataToken.ToObject(typeOfEventData, jsonSerializer);
 5196                            receivedEvent.Data = eventData;
 5197                            break;
 198                        case JTokenType.Array:
 1199                            var arrayEventData = JsonConvert.DeserializeObject(
 1200                                dataToken.ToString(),
 1201                                typeOfEventData,
 1202                                jsonSerializer.GetJsonSerializerSettings());
 1203                            receivedEvent.Data = arrayEventData;
 204                            break;
 205                        default:
 206                            break;
 207                    }
 208                }
 209            }
 210
 85211            return eventGridEvents;
 212        }
 213
 214        static JsonSerializer GetJsonSerializerWithPolymorphicSupport()
 215        {
 1216            JsonSerializerSettings deserializationSettings = new JsonSerializerSettings
 1217            {
 1218                DateFormatHandling = DateFormatHandling.IsoDateFormat,
 1219                DateTimeZoneHandling = DateTimeZoneHandling.Utc,
 1220                NullValueHandling = NullValueHandling.Ignore,
 1221                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
 1222                Converters = new List<JsonConverter>
 1223                {
 1224                    new Iso8601TimeSpanConverter()
 1225                }
 1226            };
 227
 1228            JsonSerializer jsonSerializer = JsonSerializer.Create(deserializationSettings);
 229
 230            // Note: If any of the events have polymorphic data, add converters for them here.
 231            // This enables the polymorphic deserialization for the event data.
 232            // For example, MediaJobCompletedEventData's MediaJobOutput type is polymorphic
 233            // based on the @odata.type property in the data.
 234
 1235            jsonSerializer.Converters.Add(new PolymorphicDeserializeJsonConverter<MediaJobOutput>("@odata.type"));
 236
 1237            return jsonSerializer;
 238        }
 239    }
 240}