public PSManagedIdentity(ManagedIdentity identity) { this.IdentityType = identity?.Type?.ToString(); this.PrincipalId = identity?.PrincipalId; this.TenantId = identity?.TenantId.ToString(); this.UserAssignedIdentities = identity?.UserAssignedIdentities; }
private async Task <JobProperties> CreateAndWaitForJobAsync( StorageAuthenticationType storageAuthenticationType, string devicesFileName, string configsFileName, RegistryManager registryManager, Uri containerUri, ManagedIdentity identity) { int tryCount = 0; JobProperties importJobResponse = null; JobProperties jobProperties = JobProperties.CreateForImportJob( containerUri.ToString(), containerUri.ToString(), devicesFileName, storageAuthenticationType, identity); jobProperties.ConfigurationsBlobName = configsFileName; jobProperties.IncludeConfigurations = true; while (tryCount < MaxIterationWait) { try { importJobResponse = await registryManager.ImportDevicesAsync(jobProperties).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(importJobResponse.FailureReason)) { Logger.Trace($"Job failed due to {importJobResponse.FailureReason}"); } break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { Logger.Trace($"JobQuotaExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(1000).ConfigureAwait(false); importJobResponse = await registryManager.GetJobAsync(importJobResponse?.JobId).ConfigureAwait(false); Logger.Trace($"Job {importJobResponse.JobId} is {importJobResponse.Status} with progress {importJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(importJobResponse.Status)) { break; } } return(importJobResponse); }
internal WebPubSubData(ResourceIdentifier id, string name, ResourceType type, SystemData systemData, IDictionary <string, string> tags, AzureLocation location, WebPubSubSku sku, ManagedIdentity identity, ProvisioningState?provisioningState, string externalIP, string hostName, int?publicPort, int?serverPort, string version, IReadOnlyList <PrivateEndpointConnectionData> privateEndpointConnections, IReadOnlyList <SharedPrivateLinkData> sharedPrivateLinkResources, WebPubSubTlsSettings tls, string hostNamePrefix, LiveTraceConfiguration liveTraceConfiguration, ResourceLogConfiguration resourceLogConfiguration, WebPubSubNetworkAcls networkAcls, string publicNetworkAccess, bool?disableLocalAuth, bool?disableAadAuth) : base(id, name, type, systemData, tags, location) { Sku = sku; Identity = identity; ProvisioningState = provisioningState; ExternalIP = externalIP; HostName = hostName; PublicPort = publicPort; ServerPort = serverPort; Version = version; PrivateEndpointConnections = privateEndpointConnections; SharedPrivateLinkResources = sharedPrivateLinkResources; Tls = tls; HostNamePrefix = hostNamePrefix; LiveTraceConfiguration = liveTraceConfiguration; ResourceLogConfiguration = resourceLogConfiguration; NetworkAcls = networkAcls; PublicNetworkAccess = publicNetworkAccess; DisableLocalAuth = disableLocalAuth; DisableAadAuth = disableAadAuth; }
internal GrafanaResourceData(ResourceIdentifier id, string name, ResourceType resourceType, SystemData systemData, IDictionary <string, string> tags, AzureLocation location, ResourceSku sku, GrafanaResourceProperties properties, ManagedIdentity identity) : base(id, name, resourceType, systemData, tags, location) { Sku = sku; Properties = properties; Identity = identity; }
public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi) { // arrange const string idPrefix = nameof(RegistryManager_ImportDevices); string deviceId = $"{idPrefix}-device-{StorageContainer.GetRandomSuffix(4)}"; string configId = $"{idPrefix}-config-{StorageContainer.GetRandomSuffix(4)}".ToLower(); // Configuration Id characters must be all lower-case. Logger.Trace($"Using Ids {deviceId} and {configId}."); string devicesFileName = $"{idPrefix}-devices-{StorageContainer.GetRandomSuffix(4)}.txt"; string configsFileName = $"{idPrefix}-configs-{StorageContainer.GetRandomSuffix(4)}.txt"; using RegistryManager registryManager = RegistryManager.CreateFromConnectionString(TestConfiguration.IoTHub.ConnectionString); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices)); using StorageContainer storageContainer = await StorageContainer.GetInstanceAsync(containerName).ConfigureAwait(false); Logger.Trace($"Using devices container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; using Stream devicesStream = ImportExportHelpers.BuildImportStream( new List <ExportImportDevice> { new ExportImportDevice( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas } }, ImportMode.Create), }); await UploadFileAndConfirmAsync(storageContainer, devicesStream, devicesFileName).ConfigureAwait(false); using Stream configsStream = ImportExportHelpers.BuildImportStream( new List <ImportConfiguration> { new ImportConfiguration(configId) { ImportMode = ConfigurationImportMode.CreateOrUpdateIfMatchETag, Priority = 3, Labels = { { "labelName", "labelValue" } }, TargetCondition = "*", Content = { DeviceContent = { { "properties.desired.x", 5L } }, }, Metrics = { Queries = { { "successfullyConfigured", "select deviceId from devices where properties.reported.x = 5" } } }, }, }); await UploadFileAndConfirmAsync(storageContainer, configsStream, configsFileName).ConfigureAwait(false); ManagedIdentity identity = isUserAssignedMsi ? new ManagedIdentity { UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId } : null; // act JobProperties importJobResponse = await CreateAndWaitForJobAsync( storageAuthenticationType, devicesFileName, configsFileName, registryManager, containerUri, identity) .ConfigureAwait(false); // assert importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); // should not throw due to 404, but device may not immediately appear in registry Device device = null; Configuration config = null; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); try { device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false); config = await registryManager.GetConfigurationAsync(configId).ConfigureAwait(false); break; } catch (Exception ex) { Logger.Trace($"Could not find device/config on iteration {i} due to [{ex.Message}]"); } } if (device == null) { Assert.Fail($"Device {deviceId} not found in registry manager"); } if (config == null) { Assert.Fail($"Config {configId} not found in registry manager"); } } finally { try { await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); await registryManager.RemoveConfigurationAsync(configId).ConfigureAwait(false); } catch (Exception ex) { Logger.Trace($"Failed to clean up device/config due to {ex}"); } } }
internal static ManagedGrafanaData DeserializeManagedGrafanaData(JsonElement element) { Optional <ResourceSku> sku = default; Optional <ManagedGrafanaProperties> properties = default; Optional <ManagedIdentity> identity = default; IDictionary <string, string> tags = default; AzureLocation location = default; ResourceIdentifier id = default; string name = default; ResourceType type = default; SystemData systemData = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("sku")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } sku = ResourceSku.DeserializeResourceSku(property.Value); continue; } if (property.NameEquals("properties")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } properties = ManagedGrafanaProperties.DeserializeManagedGrafanaProperties(property.Value); continue; } if (property.NameEquals("identity")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } identity = ManagedIdentity.DeserializeManagedIdentity(property.Value); continue; } if (property.NameEquals("tags")) { Dictionary <string, string> dictionary = new Dictionary <string, string>(); foreach (var property0 in property.Value.EnumerateObject()) { dictionary.Add(property0.Name, property0.Value.GetString()); } tags = dictionary; continue; } if (property.NameEquals("location")) { location = property.Value.GetString(); continue; } if (property.NameEquals("id")) { id = new ResourceIdentifier(property.Value.GetString()); continue; } if (property.NameEquals("name")) { name = property.Value.GetString(); continue; } if (property.NameEquals("type")) { type = property.Value.GetString(); continue; } if (property.NameEquals("systemData")) { systemData = JsonSerializer.Deserialize <SystemData>(property.Value.ToString()); continue; } } return(new ManagedGrafanaData(id, name, type, systemData, tags, location, sku.Value, properties.Value, identity.Value)); }
public async Task RegistryManager_ImportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi) { // arrange StorageContainer storageContainer = null; string deviceId = $"{nameof(RegistryManager_ImportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); Logger.Trace($"Using deviceId {deviceId}"); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ImportDevices)); storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); Logger.Trace($"Using container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; Stream devicesFile = ImportExportDevicesHelpers.BuildDevicesStream( new List <ExportImportDevice> { new ExportImportDevice( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas } }, ImportMode.Create), }); await UploadFileAndConfirmAsync(storageContainer, devicesFile).ConfigureAwait(false); // act JobProperties importJobResponse = null; int tryCount = 0; while (true) { try { ManagedIdentity identity = null; if (isUserAssignedMsi) { string userAssignedMsiResourceId = Configuration.IoTHub.UserAssignedMsiResourceId; identity = new ManagedIdentity { userAssignedIdentity = userAssignedMsiResourceId }; } importJobResponse = await registryManager .ImportDevicesAsync( JobProperties.CreateForImportJob( containerUri.ToString(), containerUri.ToString(), null, storageAuthenticationType)) .ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { Logger.Trace($"JobQuotaExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(1000).ConfigureAwait(false); importJobResponse = await registryManager.GetJobAsync(importJobResponse.JobId).ConfigureAwait(false); Logger.Trace($"Job {importJobResponse.JobId} is {importJobResponse.Status} with progress {importJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(importJobResponse.Status)) { break; } } // assert importJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); importJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); // should not throw due to 404, but device may not immediately appear in registry Device device = null; for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); try { device = await registryManager.GetDeviceAsync(deviceId).ConfigureAwait(false); break; } catch (Exception ex) { Logger.Trace($"Could not find device on iteration {i} due to [{ex.Message}]"); } } if (device == null) { Assert.Fail($"Device {deviceId} not found in registry manager"); } } finally { try { storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); } catch { } } }
internal static WebPubSubData DeserializeWebPubSubData(JsonElement element) { Optional <WebPubSubSku> sku = default; Optional <ManagedIdentity> identity = default; Optional <SystemData> systemData = default; IDictionary <string, string> tags = default; Location location = default; ResourceIdentifier id = default; string name = default; ResourceType type = default; Optional <ProvisioningState> provisioningState = default; Optional <string> externalIP = default; Optional <string> hostName = default; Optional <int> publicPort = default; Optional <int> serverPort = default; Optional <string> version = default; Optional <IReadOnlyList <PrivateEndpointConnectionData> > privateEndpointConnections = default; Optional <IReadOnlyList <SharedPrivateLinkData> > sharedPrivateLinkResources = default; Optional <WebPubSubTlsSettings> tls = default; Optional <string> hostNamePrefix = default; Optional <LiveTraceConfiguration> liveTraceConfiguration = default; Optional <ResourceLogConfiguration> resourceLogConfiguration = default; Optional <WebPubSubNetworkAcls> networkACLs = default; Optional <string> publicNetworkAccess = default; Optional <bool> disableLocalAuth = default; Optional <bool> disableAadAuth = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("sku")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } sku = WebPubSubSku.DeserializeWebPubSubSku(property.Value); continue; } if (property.NameEquals("identity")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } identity = ManagedIdentity.DeserializeManagedIdentity(property.Value); continue; } if (property.NameEquals("systemData")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } systemData = JsonSerializer.Deserialize <SystemData>(property.Value.ToString()); continue; } if (property.NameEquals("tags")) { Dictionary <string, string> dictionary = new Dictionary <string, string>(); foreach (var property0 in property.Value.EnumerateObject()) { dictionary.Add(property0.Name, property0.Value.GetString()); } tags = dictionary; continue; } if (property.NameEquals("location")) { location = property.Value.GetString(); continue; } if (property.NameEquals("id")) { id = new ResourceIdentifier(property.Value.GetString()); continue; } if (property.NameEquals("name")) { name = property.Value.GetString(); continue; } if (property.NameEquals("type")) { type = property.Value.GetString(); continue; } if (property.NameEquals("properties")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } foreach (var property0 in property.Value.EnumerateObject()) { if (property0.NameEquals("provisioningState")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } provisioningState = new ProvisioningState(property0.Value.GetString()); continue; } if (property0.NameEquals("externalIP")) { externalIP = property0.Value.GetString(); continue; } if (property0.NameEquals("hostName")) { hostName = property0.Value.GetString(); continue; } if (property0.NameEquals("publicPort")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } publicPort = property0.Value.GetInt32(); continue; } if (property0.NameEquals("serverPort")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } serverPort = property0.Value.GetInt32(); continue; } if (property0.NameEquals("version")) { version = property0.Value.GetString(); continue; } if (property0.NameEquals("privateEndpointConnections")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } List <PrivateEndpointConnectionData> array = new List <PrivateEndpointConnectionData>(); foreach (var item in property0.Value.EnumerateArray()) { array.Add(PrivateEndpointConnectionData.DeserializePrivateEndpointConnectionData(item)); } privateEndpointConnections = array; continue; } if (property0.NameEquals("sharedPrivateLinkResources")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } List <SharedPrivateLinkData> array = new List <SharedPrivateLinkData>(); foreach (var item in property0.Value.EnumerateArray()) { array.Add(SharedPrivateLinkData.DeserializeSharedPrivateLinkData(item)); } sharedPrivateLinkResources = array; continue; } if (property0.NameEquals("tls")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } tls = WebPubSubTlsSettings.DeserializeWebPubSubTlsSettings(property0.Value); continue; } if (property0.NameEquals("hostNamePrefix")) { hostNamePrefix = property0.Value.GetString(); continue; } if (property0.NameEquals("liveTraceConfiguration")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } liveTraceConfiguration = LiveTraceConfiguration.DeserializeLiveTraceConfiguration(property0.Value); continue; } if (property0.NameEquals("resourceLogConfiguration")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } resourceLogConfiguration = ResourceLogConfiguration.DeserializeResourceLogConfiguration(property0.Value); continue; } if (property0.NameEquals("networkACLs")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } networkACLs = WebPubSubNetworkAcls.DeserializeWebPubSubNetworkAcls(property0.Value); continue; } if (property0.NameEquals("publicNetworkAccess")) { publicNetworkAccess = property0.Value.GetString(); continue; } if (property0.NameEquals("disableLocalAuth")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } disableLocalAuth = property0.Value.GetBoolean(); continue; } if (property0.NameEquals("disableAadAuth")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } disableAadAuth = property0.Value.GetBoolean(); continue; } } continue; } } return(new WebPubSubData(id, name, type, tags, location, sku.Value, identity.Value, systemData, Optional.ToNullable(provisioningState), externalIP.Value, hostName.Value, Optional.ToNullable(publicPort), Optional.ToNullable(serverPort), version.Value, Optional.ToList(privateEndpointConnections), Optional.ToList(sharedPrivateLinkResources), tls.Value, hostNamePrefix.Value, liveTraceConfiguration.Value, resourceLogConfiguration.Value, networkACLs.Value, publicNetworkAccess.Value, Optional.ToNullable(disableLocalAuth), Optional.ToNullable(disableAadAuth))); }
public PSManagedIdentity(ManagedIdentity identity) { this.IdentityType = identity?.Type?.ToString(); this.PrincipalId = identity?.PrincipalId; this.TenantId = identity?.TenantId; }
private async Task <JobProperties> CreateAndWaitForJobAsync( StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi, string devicesFileName, string configsFileName, RegistryManager registryManager, Uri containerUri) { int tryCount = 0; ManagedIdentity identity = isUserAssignedMsi ? new ManagedIdentity { UserAssignedIdentity = TestConfiguration.IoTHub.UserAssignedMsiResourceId } : null; JobProperties exportJobResponse = JobProperties.CreateForExportJob( containerUri.ToString(), true, devicesFileName, storageAuthenticationType, identity); exportJobResponse.IncludeConfigurations = true; exportJobResponse.ConfigurationsBlobName = configsFileName; while (tryCount < MaxIterationWait) { try { exportJobResponse = await registryManager.ExportDevicesAsync(exportJobResponse).ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { Logger.Trace($"JobQuotaExceededException... waiting."); await Task.Delay(s_waitDuration).ConfigureAwait(false); continue; } } for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(s_waitDuration).ConfigureAwait(false); exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false); Logger.Trace($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(exportJobResponse.Status)) { break; } } exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); return(exportJobResponse); }
public async Task RegistryManager_ExportDevices(StorageAuthenticationType storageAuthenticationType, bool isUserAssignedMsi) { // arrange StorageContainer storageContainer = null; string deviceId = $"{nameof(RegistryManager_ExportDevices)}-{StorageContainer.GetRandomSuffix(4)}"; var registryManager = RegistryManager.CreateFromConnectionString(Configuration.IoTHub.ConnectionString); Logger.Trace($"Using deviceId {deviceId}"); try { string containerName = StorageContainer.BuildContainerName(nameof(RegistryManager_ExportDevices)); storageContainer = await StorageContainer .GetInstanceAsync(containerName) .ConfigureAwait(false); Logger.Trace($"Using container {storageContainer.Uri}"); Uri containerUri = storageAuthenticationType == StorageAuthenticationType.KeyBased ? storageContainer.SasUri : storageContainer.Uri; await registryManager .AddDeviceAsync( new Device(deviceId) { Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }, }) .ConfigureAwait(false); // act JobProperties exportJobResponse = null; int tryCount = 0; while (true) { try { ManagedIdentity identity = null; if (isUserAssignedMsi) { string userAssignedMsiResourceId = Configuration.IoTHub.UserAssignedMsiResourceId; identity = new ManagedIdentity { userAssignedIdentity = userAssignedMsiResourceId }; } exportJobResponse = await registryManager .ExportDevicesAsync( JobProperties.CreateForExportJob( containerUri.ToString(), true, null, storageAuthenticationType, identity)) .ConfigureAwait(false); break; } // Concurrent jobs can be rejected, so implement a retry mechanism to handle conflicts with other tests catch (JobQuotaExceededException) when(++tryCount < MaxIterationWait) { Logger.Trace($"JobQuotaExceededException... waiting."); await Task.Delay(_waitDuration).ConfigureAwait(false); continue; } } // wait for job to complete for (int i = 0; i < MaxIterationWait; ++i) { await Task.Delay(_waitDuration).ConfigureAwait(false); exportJobResponse = await registryManager.GetJobAsync(exportJobResponse.JobId).ConfigureAwait(false); Logger.Trace($"Job {exportJobResponse.JobId} is {exportJobResponse.Status} with progress {exportJobResponse.Progress}%"); if (!s_incompleteJobs.Contains(exportJobResponse.Status)) { break; } } // assert exportJobResponse.Status.Should().Be(JobStatus.Completed, "Otherwise import failed"); exportJobResponse.FailureReason.Should().BeNullOrEmpty("Otherwise import failed"); string content = await DownloadFileAsync(storageContainer).ConfigureAwait(false); string[] serializedDevices = content.Split(s_newlines, StringSplitOptions.RemoveEmptyEntries); bool foundDeviceInExport = false; foreach (string serializedDeivce in serializedDevices) { // The first line may be a comment to the user, so skip any lines that don't start with a json object initial character: curly brace if (serializedDeivce[0] != '{') { continue; } ExportImportDevice device = JsonConvert.DeserializeObject <ExportImportDevice>(serializedDeivce); if (StringComparer.Ordinal.Equals(device.Id, deviceId)) { Logger.Trace($"Found device in export as [{serializedDeivce}]"); foundDeviceInExport = true; break; } } foundDeviceInExport.Should().BeTrue("Expected device did not appear in the export"); } finally { try { storageContainer?.Dispose(); await registryManager.RemoveDeviceAsync(deviceId).ConfigureAwait(false); } catch { } } }