/// <summary> /// Create patch twin model to upload /// </summary> /// <param name="existing"></param> /// <param name="update"></param> public static DeviceTwinModel Patch(this EndpointRegistration existing, EndpointRegistration update) { var twin = new DeviceTwinModel { Etag = existing?.Etag, Tags = new Dictionary <string, JToken>(), Properties = new TwinPropertiesModel { Desired = new Dictionary <string, JToken>() } }; // Tags if (update?.ApplicationId != null && update.ApplicationId != existing?.ApplicationId) { twin.Tags.Add(nameof(ApplicationId), update.ApplicationId); } if (update?.IsDisabled != null && update.IsDisabled != existing?.IsDisabled) { twin.Tags.Add(nameof(EntityRegistration.IsDisabled), (update?.IsDisabled ?? false) ? true : (bool?)null); twin.Tags.Add(nameof(EntityRegistration.NotSeenSince), (update?.IsDisabled ?? false) ? DateTime.UtcNow : (DateTime?)null); } if (update?.SiteOrGatewayId != existing?.SiteOrGatewayId) { twin.Tags.Add(nameof(EntityRegistration.SiteOrGatewayId), update?.SiteOrGatewayId); } if (update?.SupervisorId != existing?.SupervisorId) { twin.Tags.Add(nameof(EndpointRegistration.SupervisorId), update?.SupervisorId); } if (update?.DiscovererId != existing?.DiscovererId) { twin.Tags.Add(nameof(EndpointRegistration.DiscovererId), update?.DiscovererId); } if (update?.SiteId != existing?.SiteId) { twin.Tags.Add(nameof(EntityRegistration.SiteId), update?.SiteId); } var certUpdate = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (!(certUpdate ?? true)) { twin.Tags.Add(nameof(EntityRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); twin.Tags.Add(nameof(EntityRegistration.Thumbprint), update?.Certificate?.DecodeAsByteArray()?.ToSha1Hash()); } twin.Tags.Add(nameof(EntityRegistration.DeviceType), update?.DeviceType); if (update?.EndpointRegistrationUrl != null && update.EndpointRegistrationUrl != existing?.EndpointRegistrationUrl) { twin.Tags.Add(nameof(EndpointRegistration.EndpointUrlLC), update.EndpointUrlLC); twin.Tags.Add(nameof(EndpointRegistration.EndpointRegistrationUrl), update.EndpointRegistrationUrl); } if (update?.SecurityLevel != existing?.SecurityLevel) { twin.Tags.Add(nameof(EndpointRegistration.SecurityLevel), update?.SecurityLevel == null ? null : JToken.FromObject(update?.SecurityLevel)); } if (update?.Activated != null && update.Activated != existing?.Activated) { twin.Tags.Add(nameof(EndpointRegistration.Activated), update?.Activated); } var methodEqual = update?.AuthenticationMethods.DecodeAsList().SetEqualsSafe( existing?.AuthenticationMethods?.DecodeAsList(), JToken.DeepEquals); if (!(methodEqual ?? true)) { twin.Tags.Add(nameof(EndpointRegistration.AuthenticationMethods), update?.AuthenticationMethods == null ? null : JToken.FromObject(update.AuthenticationMethods, new JsonSerializer { NullValueHandling = NullValueHandling.Ignore })); } // Endpoint Property if (update?.EndpointUrl != null && update.EndpointUrl != existing?.EndpointUrl) { twin.Properties.Desired.Add(nameof(EndpointRegistration.EndpointUrl), update.EndpointUrl); } var urlsEqual = update?.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( existing?.AlternativeUrls?.DecodeAsList()); if (!(urlsEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.AlternativeUrls), update?.AlternativeUrls == null ? null : JToken.FromObject(update.AlternativeUrls)); } if (update?.SecurityMode != null && update.SecurityMode != existing?.SecurityMode) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityMode), JToken.FromObject(update.SecurityMode)); } if (update?.SecurityPolicy != null && update?.SecurityPolicy != existing?.SecurityPolicy) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityPolicy), update.SecurityPolicy); } var certEqual = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (update?.Certificate != null && !(certEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); } // Recalculate identity var reportedEndpointUrl = existing?.EndpointRegistrationUrl; if (update?.EndpointRegistrationUrl != null) { reportedEndpointUrl = update.EndpointRegistrationUrl; } if (reportedEndpointUrl == null) { throw new ArgumentException(nameof(EndpointRegistration.EndpointUrl)); } var applicationId = existing?.ApplicationId; if (update?.ApplicationId != null) { applicationId = update.ApplicationId; } if (applicationId == null) { throw new ArgumentException(nameof(EndpointRegistration.ApplicationId)); } var securityMode = existing?.SecurityMode; if (update?.SecurityMode != null) { securityMode = update.SecurityMode; } var securityPolicy = existing?.SecurityPolicy; if (update?.SecurityPolicy != null) { securityPolicy = update.SecurityPolicy; } twin.Id = EndpointInfoModelEx.CreateEndpointId( applicationId, reportedEndpointUrl, securityMode, securityPolicy); if (existing?.DeviceId != twin.Id) { twin.Etag = null; // Force creation of new identity } return(twin); }
/// <summary> /// Create patch twin model to upload /// </summary> /// <param name="existing"></param> /// <param name="update"></param> public static DeviceTwinModel Patch(this EndpointRegistration existing, EndpointRegistration update) { var twin = BaseRegistrationEx.PatchBase(existing, update); // Tags if (update?.EndpointRegistrationUrl != null && update.EndpointRegistrationUrl != existing?.EndpointRegistrationUrl) { twin.Tags.Add(nameof(EndpointRegistration.EndpointUrlLC), update.EndpointUrlLC); twin.Tags.Add(nameof(EndpointRegistration.EndpointRegistrationUrl), update.EndpointRegistrationUrl); } if (update?.SecurityLevel != existing?.SecurityLevel) { twin.Tags.Add(nameof(EndpointRegistration.SecurityLevel), update?.SecurityLevel == null ? null : JToken.FromObject(update?.SecurityLevel)); } if (update?.Activated != null && update.Activated != existing?.Activated) { twin.Tags.Add(nameof(EndpointRegistration.Activated), update?.Activated); } var methodEqual = update?.AuthenticationMethods.DecodeAsList().SetEqualsSafe( existing?.AuthenticationMethods?.DecodeAsList(), JToken.DeepEquals); if (!(methodEqual ?? true)) { twin.Tags.Add(nameof(EndpointRegistration.AuthenticationMethods), update?.AuthenticationMethods == null ? null : JToken.FromObject(update.AuthenticationMethods, new JsonSerializer { NullValueHandling = NullValueHandling.Ignore })); } // Endpoint Property if (update?.EndpointUrl != null && update.EndpointUrl != existing?.EndpointUrl) { twin.Properties.Desired.Add(nameof(EndpointRegistration.EndpointUrl), update.EndpointUrl); } var urlsEqual = update?.AlternativeUrls.DecodeAsList().ToHashSetSafe().SetEqualsSafe( existing?.AlternativeUrls?.DecodeAsList()); if (!(urlsEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.AlternativeUrls), update?.AlternativeUrls == null ? null : JToken.FromObject(update.AlternativeUrls)); } if (update?.SecurityMode != null && update.SecurityMode != existing?.SecurityMode) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityMode), JToken.FromObject(update.SecurityMode)); } if (update?.SecurityPolicy != null && update?.SecurityPolicy != existing?.SecurityPolicy) { twin.Properties.Desired.Add(nameof(EndpointRegistration.SecurityPolicy), update.SecurityPolicy); } if (update?.CredentialType != existing?.CredentialType) { twin.Properties.Desired.Add(nameof(EndpointRegistration.CredentialType), update?.CredentialType == null ? null : JToken.FromObject(update?.CredentialType)); } if (!JToken.DeepEquals(update?.Credential, existing?.Credential)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Credential), update?.Credential); } var certEqual = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe( existing?.Certificate.DecodeAsByteArray()); if (update?.Certificate != null && !(certEqual ?? true)) { twin.Properties.Desired.Add(nameof(EndpointRegistration.Certificate), update?.Certificate == null ? null : JToken.FromObject(update.Certificate)); } // Recalculate identity var reportedEndpointUrl = existing?.EndpointRegistrationUrl; if (update?.EndpointRegistrationUrl != null) { reportedEndpointUrl = update.EndpointRegistrationUrl; } if (reportedEndpointUrl == null) { throw new ArgumentException(nameof(EndpointRegistration.EndpointUrl)); } var applicationId = existing?.ApplicationId; if (update?.ApplicationId != null) { applicationId = update.ApplicationId; } if (applicationId == null) { throw new ArgumentException(nameof(EndpointRegistration.ApplicationId)); } var securityMode = existing?.SecurityMode; if (update?.SecurityMode != null) { securityMode = update.SecurityMode; } var securityPolicy = existing?.SecurityPolicy; if (update?.SecurityPolicy != null) { securityPolicy = update.SecurityPolicy; } twin.Id = EndpointInfoModelEx.CreateEndpointId( applicationId, reportedEndpointUrl, securityMode, securityPolicy); if (existing?.DeviceId != twin.Id) { twin.Etag = null; // Force creation of new identity } return(twin); }