// This method updates local state and should be called only after acquiring edgeHubConfigLock
        async Task <Option <EdgeHubConfig> > GetConfigInternal()
        {
            Option <EdgeHubConfig> edgeHubConfig;

            try
            {
                Core.IMessage message = await this.twinManager.GetTwinAsync(this.id);

                Twin twin = this.twinMessageConverter.FromMessage(message);
                this.lastDesiredProperties = Option.Some(twin.Properties.Desired);
                try
                {
                    var desiredProperties = JsonConvert.DeserializeObject <EdgeHubDesiredProperties>(twin.Properties.Desired.ToJson());
                    edgeHubConfig = Option.Some(EdgeHubConfigParser.GetEdgeHubConfig(desiredProperties, this.routeFactory));
                    await this.UpdateReportedProperties(twin.Properties.Desired.Version, new LastDesiredStatus(200, string.Empty));

                    Events.GetConfigSuccess();
                }
                catch (Exception ex)
                {
                    await this.UpdateReportedProperties(twin.Properties.Desired.Version, new LastDesiredStatus(400, $"Error while parsing desired properties - {ex.Message}"));

                    throw;
                }
            }
            catch (Exception ex)
            {
                edgeHubConfig = Option.None <EdgeHubConfig>();
                Events.ErrorGettingEdgeHubConfig(ex);
            }

            return(edgeHubConfig);
        }
        public async Task <Option <EdgeHubConfig> > GetConfig()
        {
            try
            {
                Option <IMessage> twinMessage = await this.twinManager.GetCachedTwinAsync(this.id);

                var config = twinMessage.FlatMap((message) =>
                {
                    Shared.Twin twin = this.twinMessageConverter.FromMessage(message);

                    if (twin.Properties.Desired.Count > 0)
                    {
                        var desiredProperties = JsonConvert.DeserializeObject <EdgeHubDesiredProperties>(twin.Properties.Desired.ToJson());
                        return(Option.Some(EdgeHubConfigParser.GetEdgeHubConfig(desiredProperties, this.routeFactory)));
                    }
                    else
                    {
                        return(Option.None <EdgeHubConfig>());
                    }
                });

                return(config);
            }
            catch (Exception e)
            {
                Log.LogWarning(HubCoreEventIds.LocalEdgeHubConfig, e, "Failed to get local config");
                return(Option.None <EdgeHubConfig>());
            }
        }
        // This method updates local state and should be called only after acquiring edgeHubConfigLock
        async Task <Option <EdgeHubConfig> > PatchDesiredProperties(TwinCollection baseline, TwinCollection patch)
        {
            LastDesiredStatus      lastDesiredStatus;
            Option <EdgeHubConfig> edgeHubConfig;

            try
            {
                string desiredPropertiesJson = JsonEx.Merge(baseline, patch, true);
                this.lastDesiredProperties = Option.Some(new TwinCollection(desiredPropertiesJson));
                var desiredPropertiesPatch = JsonConvert.DeserializeObject <EdgeHubDesiredProperties>(desiredPropertiesJson);
                edgeHubConfig     = Option.Some(EdgeHubConfigParser.GetEdgeHubConfig(desiredPropertiesPatch, this.routeFactory));
                lastDesiredStatus = new LastDesiredStatus(200, string.Empty);
                Events.PatchConfigSuccess();
            }
            catch (Exception ex)
            {
                lastDesiredStatus = new LastDesiredStatus(400, $"Error while parsing desired properties - {ex.Message}");
                edgeHubConfig     = Option.None <EdgeHubConfig>();
                Events.ErrorPatchingDesiredProperties(ex);
            }

            await this.UpdateReportedProperties(patch.Version, lastDesiredStatus);

            return(edgeHubConfig);
        }