public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            // After this is deployed, you need to turn the Managed Identity Status to "On",
            // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role to this function identity
            // in order for this function to be authorized on ADT APIs.

            log.LogInformation(eventGridEvent.Data.ToString());
            try
            {
                // Authenticate on ADT APIs
                var cred   = new ManagedIdentityCredential(adtAppId);
                var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                });
                log.LogInformation($"ADT service client connection created.");

                if (client != null)
                {
                    if (eventGridEvent != null && eventGridEvent.Data != null)
                    {
                        #region Open this region for message format information
                        // Telemetry message format
                        //{
                        //  "properties": { },
                        //  "systemProperties":
                        // {
                        //    "iothub-connection-device-id": "thermostat1",
                        //    "iothub-connection-auth-method": "{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}",
                        //    "iothub-connection-auth-generation-id": "637199981642612179",
                        //    "iothub-enqueuedtime": "2020-03-18T18:35:08.269Z",
                        //    "iothub-message-source": "Telemetry"
                        //  },
                        //  "body": "eyJUZW1wZXJhdHVyZSI6NzAuOTI3MjM0MDg3MTA1NDg5fQ=="
                        //}
                        #endregion

                        // Reading deviceId from message headers
                        log.LogInformation(eventGridEvent.Data.ToString());
                        JObject job      = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
                        string  deviceId = (string)job["systemProperties"]["iothub-connection-device-id"];
                        log.LogInformation($"Found device: {deviceId}");

                        // Extracting temperature from device telemetry
                        byte[] body         = Convert.FromBase64String(job["body"].ToString());
                        var    value        = Encoding.ASCII.GetString(body);
                        var    bodyProperty = (JObject)JsonConvert.DeserializeObject(value);
                        JToken temperature  = bodyProperty["Temperature"];
                        log.LogInformation($"Device Temperature is ({temperature.Type}): {temperature}");

                        // Update device Temperature property
                        await AdtUtilities.UpdateTwinPropertyAsync(client, deviceId, "/Temperature", temperature.Value <float>(), log);
                    }
                }
            }
            catch (Exception e)
            {
                log.LogError($"Error: {e.Message}");
            }
        }
        public static async Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            log.LogInformation("Start execution");
            // After this is deployed, you'll need to turn the Azure Function Identity Status "On",
            // grab Object ID of the function, and assign "Azure Digital Twins Owner (Preview)" role to this function identity
            // in order for this function to be authorized on ADT APIs.
            //
            // If you are following "Tutorial: Connect an end-to-end solution" in the Azure Digital Twins documentation,
            // you have done this already with an equivalent CLI step in the "Assign permissions to the function app" section.

            DigitalTwinsClient client;

            // Authenticate on ADT APIs
            try
            {
                var credentials = new DefaultAzureCredential();
                client = new DigitalTwinsClient(new Uri(adtServiceUrl), credentials, new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                });
                log.LogInformation("ADT service client connection created.");
            }
            catch (Exception e)
            {
                log.LogError($"ADT service client connection failed. {e}");
                return;
            }

            if (client != null)
            {
                if (eventGridEvent != null && eventGridEvent.Data != null)
                {
                    string  twinId  = eventGridEvent.Subject.ToString();
                    JObject message = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());

                    log.LogInformation($"Reading event from {twinId}: {eventGridEvent.EventType}: {message["data"]}");

                    //Find and update parent Twin
                    string parentId = await AdtUtilities.FindParentAsync(client, twinId, "contains", log);

                    if (parentId != null)
                    {
                        // Read properties which values have been changed in each operation
                        foreach (var operation in message["data"]["patch"])
                        {
                            string opValue = (string)operation["op"];
                            if (opValue.Equals("replace"))
                            {
                                string propertyPath = ((string)operation["path"]);

                                if (propertyPath.Equals("/Temperature"))
                                {
                                    await AdtUtilities.UpdateTwinPropertyAsync(client, parentId, propertyPath, operation["value"].Value <float>(), log);
                                }
                            }
                        }
                    }
                }
            }
        }
        public static async Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            log.LogInformation("Start execution");
            // After this is deployed, you need to turn the Identity Status "On",
            // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role to this function identity
            // in order for this function to be authorize on ADT APIs.

            DigitalTwinsClient client;

            // Authenticate on ADT APIs
            try
            {
                ManagedIdentityCredential cred = new ManagedIdentityCredential(adtAppId);
                client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                });
                log.LogInformation("ADT service client connection created.");
            }
            catch (Exception e)
            {
                log.LogError($"ADT service client connection failed. {e}");
                return;
            }

            if (client != null)
            {
                try
                {
                    if (eventGridEvent != null && eventGridEvent.Data != null)
                    {
                        string  twinId  = eventGridEvent.Subject.ToString();
                        JObject message = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());

                        log.LogInformation($"Reading event from {twinId}: {eventGridEvent.EventType}: {message["data"]}");

                        //Find and update parent Twin
                        string parentId = await AdtUtilities.FindParentAsync(client, twinId, "contains", log);

                        if (parentId != null)
                        {
                            // Read properties which values have been changed in each operation
                            foreach (var operation in message["data"]["patch"])
                            {
                                string opValue = (string)operation["op"];
                                if (opValue.Equals("replace"))
                                {
                                    string propertyPath  = ((string)operation["path"]);
                                    object propertyValue = (object)operation["value"];

                                    if (propertyPath.Equals("/Temperature"))
                                    {
                                        await AdtUtilities.UpdateTwinPropertyAsync(client, parentId, propertyPath, propertyValue, log);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    log.LogError(e.ToString());
                }
            }
        }
        public static async Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            // After this is deployed, you need to turn the Identity Status "On",
            // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role to this function identity
            // in order for this function to be authorize on ADT APIs.

            DigitalTwinsClient client = null;

            log.LogInformation("start execution");
            // Authenticate on ADT APIs
            try
            {
                ManagedIdentityCredential cred = new ManagedIdentityCredential(adtAppId);
                client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                });
                log.LogInformation($"ADT service client connection created.");
            }
            catch (Exception e)
            {
                log.LogError($"ADT service client connection failed. " + e.ToString());
                return;
            }

            if (client != null)
            {
                try
                {
                    if (eventGridEvent != null && eventGridEvent.Data != null)
                    {
                        #region Open this region for message format information
                        // Known Issue: you cannot read the header event type in telemetry or notifications,
                        // you cannot read notification properties for now until CE format it's implemented
                        // Therefore you have to parse the notification for "Operations" (for now)
                        // Read property change events, format looks like this
                        //{
                        //  "data":
                        //  {
                        //    "TwinId": "room1",
                        //    "Operations":
                        //    [
                        //        {"op": "replace", "path": "/Temperature", "value": 70},
                        //        {"op": "replace",  "path": "/Humidity","value": 49 }
                        //    ]
                        //  }
                        // }
                        // Device Telemetry message
                        //{
                        //  "properties": { },
                        //  "systemProperties":
                        // {
                        //    "iothub-connection-device-id": "thermostat1",
                        //    "iothub-connection-auth-method": "{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}",
                        //    "iothub-connection-auth-generation-id": "637199981642612179",
                        //    "iothub-enqueuedtime": "2020-03-18T18:35:08.269Z",
                        //    "iothub-message-source": "Telemetry"
                        //  },
                        //  "body": "eyJUZW1wZXJhdHVyZSI6NzAuOTI3MjM0MDg3MTA1NDg5fQ=="
                        //}
                        #endregion

                        string evt = eventGridEvent.Data.ToString();
                        log.LogInformation(evt);
                        JObject message = (JObject)JsonConvert.DeserializeObject(evt);

                        // Read twin id
                        string twinId = (string)message["TwinId"];
                        log.LogInformation($"Found updates on twin: {twinId}");

                        // Validate "Operations" and TwinId
                        if ((message["Operations"] == null || message["Operations"].Count() == 0) && String.IsNullOrEmpty(twinId))
                        {
                            log.LogInformation($"No twin property change events");
                        }

                        //string parent = await FindParent(twinId, "contains", log);
                        string parentId = await AdtUtilities.FindParentByQuery(client, twinId, log);

                        if (parentId != null)
                        {
                            // Read properties which values have been changed in each operation
                            foreach (var operation in message["Operations"])
                            {
                                string opValue = (string)operation["op"];
                                if (opValue.Equals("replace"))
                                {
                                    string propertyPath  = ((string)operation["path"]);
                                    string propertyValue = (string)operation["value"];

                                    if (propertyPath.Equals("/Temperature"))
                                    {
                                        await AdtUtilities.UpdateTwinProperty(client, parentId, "replace", propertyPath, "double", propertyValue, log);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    log.LogError($"*** Unable to create client connection {e}");
                }
            }
        }