Id's van IoT Hub-apparaten bulksgewijs importeren en exporteren

Elke IoT-hub heeft een identiteitsregister dat u kunt gebruiken om apparaatbronnen in de service te maken. Met het identiteitsregister kunt u ook de toegang tot de apparaatgerichte eindpunten beheren. In dit artikel wordt beschreven hoe u apparaat-id's bulksgewijs importeert en exporteert vanuit een identiteitsregister met behulp van het voorbeeld ImportExportDeviceSample dat is opgenomen in de Microsoft Azure IoT SDK voor .NET. Zie Een Azure IoT-hub handmatig migreren met behulp van een Azure Resource Manager-sjabloon voor meer informatie over hoe u deze mogelijkheid kunt gebruiken bij het migreren van een IoT-hub naar een andere regio.

Notitie

IoT Hub heeft onlangs ondersteuning voor virtuele netwerken toegevoegd in een beperkt aantal regio's. Deze functie beveiligt import- en exportbewerkingen en elimineert de noodzaak om sleutels voor verificatie door te geven. Momenteel is ondersteuning voor virtuele netwerken alleen beschikbaar in deze regio's: WestUS2, EastUS en SouthCentralUS. Zie IoT Hub-ondersteuning voor virtuele netwerken voor meer informatie over ondersteuning voor virtuele netwerken en de API-aanroepen om het te implementeren.

Import- en exportbewerkingen vinden plaats in de context van taken waarmee u bulkservicebewerkingen kunt uitvoeren op een IoT-hub.

De Klasse RegistryManager in de SDK bevat de methoden ExportDevicesAsync en ImportDevicesAsync die gebruikmaken van het Taakframework . Met deze methoden kunt u het volledige id-register van een IoT Hub exporteren, importeren en synchroniseren.

In dit artikel wordt beschreven hoe u de klasse RegistryManager en het taaksysteem gebruikt om bulksgewijs importeren en exporteren van apparaten naar en van het identiteitsregister van een IoT-hub uit te voeren. U kunt de Azure IoT Hub Device Provisioning Service ook gebruiken om Just-In-Time-inrichting in te schakelen voor een of meer IoT-hubs. Zie de documentatie van de inrichtingsservice voor meer informatie.

Notitie

Sommige codefragmenten in dit artikel zijn opgenomen in het voorbeeld van de ImportExportDevicesSample-service die is geleverd met de Microsoft Azure IoT SDK voor .NET. Het voorbeeld bevindt zich in de map van de /iothub/service/samples/how to guides/ImportExportDevicesSample SDK en, waar opgegeven, codefragmenten worden opgenomen uit het ImportExportDevicesSample.cs bestand voor dat SDK-voorbeeld. Zie azure IoT Hub-servicevoorbeelden voor C# voor meer informatie over het voorbeeld ImportExportDevicesSample en andere servicevoorbeelden die zijn opgenomen in de Azure IoT SDK for.NET.

Wat zijn jobs?

Identiteitsregisterbewerkingen maken gebruik van het taaksysteem wanneer de bewerking:

  • Heeft een potentieel lange uitvoeringstijd vergeleken met standaardruntimebewerkingen.

  • Retourneert een grote hoeveelheid gegevens aan de gebruiker.

In plaats van één API-aanroep die wacht of blokkeert op het resultaat van de bewerking, maakt de bewerking asynchroon een taak voor die IoT-hub. De bewerking retourneert vervolgens onmiddellijk een JobProperties-object .

In het volgende C#-codefragment ziet u hoe u een exporttaak maakt:

// Call an export job on the IoT hub to retrieve all devices
JobProperties exportJob = await 
  registryManager.ExportDevicesAsync(containerSasUri, false);

Notitie

Als u de RegistryManager-klasse in uw C#-code wilt gebruiken, voegt u het NuGet-pakket Microsoft.Azure.Devices toe aan uw project. De klasse RegistryManager bevindt zich in de naamruimte Microsoft.Azure.Devices .

U kunt de Klasse RegistryManager gebruiken om een query uit te voeren op de status van de taak met behulp van de geretourneerde metagegevens van JobProperties . Als u een exemplaar van de klasse RegistryManager wilt maken, gebruikt u de methode CreateFrom Verbinding maken ionString.

RegistryManager registryManager =
  RegistryManager.CreateFromConnectionString("{your IoT Hub connection string}");

U vindt de verbindingsreeks voor uw IoT-hub in Azure Portal:

  1. Ga naar uw IoT-hub.

  2. Selecteer Beleid voor gedeelde toegang.

  3. Selecteer een beleid, rekening houdend met de machtigingen die u nodig hebt.

  4. Kopieer de verbindingsreeks voor dat beleid.

Het volgende C#-codefragment, van de WaitForJobAsync-methode in het SDK-voorbeeld, laat zien hoe u elke vijf seconden kunt peilen om te zien of de taak is voltooid:

// Wait until job is finished
while (true)
{
    job = await registryManager.GetJobAsync(job.JobId);
    if (job.Status == JobStatus.Completed
        || job.Status == JobStatus.Failed
        || job.Status == JobStatus.Cancelled)
    {
        // Job has finished executing
        break;
    }
    Console.WriteLine($"\tJob status is {job.Status}...");

    await Task.Delay(TimeSpan.FromSeconds(5));
}

Notitie

Als uw opslagaccount firewallconfiguraties heeft die de connectiviteit van IoT Hub beperken, kunt u overwegen om uitzonderingen van vertrouwde first party's van Microsoft te gebruiken (beschikbaar in bepaalde regio's voor IoT-hubs met beheerde service-identiteit).

Limieten voor het importeren/exporteren van apparaten

Voor alle IoT Hub-lagen is slechts één actieve import- of exporttaak toegestaan. IoT Hub heeft ook limieten voor de snelheid van taakbewerkingen. Zie Quota en beperking van IoT Hub voor meer informatie.

Apparaten exporteren

Gebruik de methode ExportDevicesAsync om het volledige id-register van een IoT Hub te exporteren naar een Azure Storage-blobcontainer met behulp van een SAS (Shared Access Signature). Met deze methode kunt u betrouwbare back-ups van uw apparaatgegevens maken in een blobcontainer die u beheert.

Voor de methode ExportDevicesAsync zijn twee parameters vereist:

  • Een tekenreeks die een URI van een blobcontainer bevat. Deze URI moet een SAS-token bevatten dat schrijftoegang verleent tot de container. Met de taak maakt u een blok-blob in deze container om de geserialiseerde exportapparaatgegevens op te slaan. Het SAS-token moet de volgende machtigingen bevatten:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    
  • Een Booleaanse waarde die aangeeft of u verificatiesleutels wilt uitsluiten van uw exportgegevens. Als dit onwaar is, worden verificatiesleutels opgenomen in exportuitvoer. Anders worden sleutels geëxporteerd als null.

In het volgende C#-codefragment ziet u hoe u een exporttaak kunt initiëren die verificatiesleutels voor apparaten in de exportgegevens bevat en vervolgens pollt naar voltooiing:

// Call an export job on the IoT Hub to retrieve all devices
JobProperties exportJob = 
  await registryManager.ExportDevicesAsync(containerSasUri, false);

// Wait until job is finished
while(true)
{
    exportJob = await registryManager.GetJobAsync(exportJob.JobId);
    if (exportJob.Status == JobStatus.Completed || 
        exportJob.Status == JobStatus.Failed ||
        exportJob.Status == JobStatus.Cancelled)
    {
    // Job has finished executing
    break;
    }

    await Task.Delay(TimeSpan.FromSeconds(5));
}

U vindt vergelijkbare code in de methode ExportDevicesAsync uit het SDK-voorbeeld. De taak slaat de uitvoer op in de opgegeven blobcontainer als blok-blob met de naam devices.txt. De uitvoergegevens bestaan uit geserialiseerde JSON-apparaatgegevens, met één apparaat per regel.

In het volgende voorbeeld ziet u de uitvoergegevens:

{"id":"Device1","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device2","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device3","eTag":"MA==","status":"disabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device4","eTag":"MA==","status":"disabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}
{"id":"Device5","eTag":"MA==","status":"enabled","authentication":{"symmetricKey":{"primaryKey":"abc=","secondaryKey":"def="}}}

Als een apparaat dubbelgegevens bevat, worden de dubbelgegevens ook samen met de apparaatgegevens geëxporteerd. In het volgende voorbeeld ziet u deze indeling. Alle gegevens van de regel 'twinETag' tot het einde dubbele gegevens zijn.

{
   "id":"export-6d84f075-0",
   "eTag":"MQ==",
   "status":"enabled",
   "authentication":null,
   "twinETag":"AAAAAAAAAAI=",
   "tags":{
      "Location":"LivingRoom"
   },
   "properties":{
      "desired":{
         "Thermostat":{
            "Temperature":75.1,
            "Unit":"F"
         },
      },
      "reported":{}
   }
}

Als u toegang nodig hebt tot deze gegevens in code, kunt u deze gegevens deserialiseren met behulp van de klasse ExportImportDevice . In het volgende C#-codefragment, uit de methode ReadFromBlobAsync in het SDK-voorbeeld, ziet u hoe u apparaatgegevens leest die eerder uit ExportImportDevice naar een BlobClient-exemplaar zijn geëxporteerd:

private static async Task<List<string>> ReadFromBlobAsync(BlobClient blobClient)
{
    // Read the blob file of devices, import each row into a list.
    var contents = new List<string>();

    using Stream blobStream = await blobClient.OpenReadAsync();
    using var streamReader = new StreamReader(blobStream, Encoding.UTF8);
    while (streamReader.Peek() != -1)
    {
        string line = await streamReader.ReadLineAsync();
        contents.Add(line);
    }

    return contents;
}

Apparaten importeren

Met de methode ImportDevicesAsync in de klasse RegistryManager kunt u bulksgewijze import- en synchronisatiebewerkingen uitvoeren in een IoT Hub-identiteitsregister. Net als de methode ExportDevicesAsync gebruikt de methode ImportDevicesAsync het jobframework .

Zorg ervoor dat u de methode ImportDevicesAsync gebruikt, omdat naast het inrichten van nieuwe apparaten in uw identiteitsregister ook bestaande apparaten kunnen worden bijgewerkt en verwijderd.

Waarschuwing

Een importbewerking kan niet ongedaan worden gemaakt. Maak altijd een back-up van uw bestaande gegevens met behulp van de methode ExportDevicesAsync naar een andere blobcontainer voordat u bulksgewijs wijzigingen aanbrengt in uw identiteitsregister.

De methode ImportDevicesAsync heeft twee parameters:

  • Een tekenreeks die een URI van een Azure Storage-blobcontainer bevat die moet worden gebruikt als invoer voor de taak. Deze URI moet een SAS-token bevatten dat leestoegang verleent tot de container. Deze container moet een blob bevatten met de naam devices.txt die de geserialiseerde apparaatgegevens bevat die moeten worden geïmporteerd in uw identiteitsregister. De importgegevens moeten apparaatgegevens bevatten in dezelfde JSON-indeling die de ExportImportDevice-taak gebruikt wanneer er een devices.txt blob wordt gemaakt. Het SAS-token moet de volgende machtigingen bevatten:

    SharedAccessBlobPermissions.Read
    
  • Een tekenreeks die een URI van een Azure Storage-blobcontainer bevat die moet worden gebruikt als uitvoer van de taak. De taak maakt een blok-blob in deze container om foutinformatie op te slaan uit de voltooide importtaak. Het SAS-token moet de volgende machtigingen bevatten:

    SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read 
       | SharedAccessBlobPermissions.Delete
    

Notitie

De twee parameters kunnen verwijzen naar dezelfde blobcontainer. Met de afzonderlijke parameters kunt u eenvoudig meer controle over uw gegevens inschakelen, omdat voor de uitvoercontainer aanvullende machtigingen zijn vereist.

In het volgende C#-codefragment ziet u hoe u een importtaak start:

JobProperties importJob = 
   await registryManager.ImportDevicesAsync(containerSasUri, containerSasUri);

Deze methode kan ook worden gebruikt om de gegevens voor de apparaatdubbel te importeren. De indeling voor de gegevensinvoer is hetzelfde als de indeling die wordt weergegeven in de sectie ExportDevicesAsync . Op deze manier kunt u de geëxporteerde gegevens opnieuw importeren.

Importgedrag

U kunt de methode ImportDevicesAsync gebruiken om de volgende bulkbewerkingen uit te voeren in uw identiteitsregister:

  • Bulkregistratie van nieuwe apparaten
  • Bulksgewijs verwijderen van bestaande apparaten
  • Wijzigingen in bulkstatus (apparaten in- of uitschakelen)
  • Bulktoewijzing van nieuwe apparaatverificatiesleutels
  • Bulksgewijs automatisch genereren van apparaatverificatiesleutels
  • Bulkupdate van dubbelgegevens

U kunt elke combinatie van de voorgaande bewerkingen uitvoeren binnen één ImportDevicesAsync-aanroep . U kunt bijvoorbeeld nieuwe apparaten registreren en bestaande apparaten tegelijkertijd verwijderen of bijwerken. Wanneer u samen met de methode ExportDevicesAsync gebruikt, kunt u al uw apparaten volledig van de ene IoT-hub naar de andere migreren.

Gebruik de optionele eigenschap importMode in de importserialisatiegegevens voor elk apparaat om het importproces per apparaat te beheren. De eigenschap importMode heeft de volgende opties:

  • Maken
  • CreateOrUpdate (standaard)
  • CreateOrUpdateIfMatchETag
  • Delete
  • DeleteIfMatchETag
  • Bijwerken
  • UpdateIfMatchETag
  • UpdateTwin
  • UpdateTwinIfMatcheTag

Zie ImportMode voor meer informatie over elk van deze opties voor de importmodus

Problemen met importtaken oplossen

Het gebruik van een importtaak voor het maken van apparaten kan mislukken met een quotumprobleem wanneer deze zich dicht bij de limiet voor het aantal apparaten van de IoT-hub bevinden. Deze fout kan ook optreden als het totale aantal apparaten nog steeds lager is dan de quotumlimiet. De IotHubQuotaExceeded-fout (403002) wordt geretourneerd met het volgende foutbericht: 'Totaal aantal apparaten op IotHub heeft het toegewezen quotum overschreden'.

Als u deze fout krijgt, kunt u de volgende query gebruiken om het totale aantal apparaten te retourneren dat is geregistreerd op uw IoT-hub:

SELECT COUNT() as totalNumberOfDevices FROM devices

Zie IoT Hub-limieten voor informatie over het totale aantal apparaten dat kan worden geregistreerd bij een IoT-hub.

Als er nog quota beschikbaar zijn, kunt u de blob voor taakuitvoer onderzoeken op apparaten die zijn mislukt met de fout IotHubQuotaExceeded (403002 ). Vervolgens kunt u deze apparaten afzonderlijk toevoegen aan de IoT-hub. U kunt bijvoorbeeld de methoden AddDeviceAsync of AddDeviceWithTwinAsync gebruiken. Probeer de apparaten niet toe te voegen met behulp van een andere taak, omdat er mogelijk dezelfde fout optreedt.

Voorbeeld van het importeren van apparaten: bulksgewijs inrichten van apparaten

In het volgende C#-codefragment, uit de methode GenerateDevicesAsync in het SDK-voorbeeld, ziet u hoe u meerdere apparaatidentiteiten genereert die:

  • Neem verificatiesleutels op.
  • Schrijf die apparaatgegevens naar een blok-blob.
  • Importeer de apparaten in het identiteitsregister.
private async Task GenerateDevicesAsync(RegistryManager registryManager, int numToAdd)
{
    var stopwatch = Stopwatch.StartNew();

    Console.WriteLine($"Creating {numToAdd} devices for the source IoT hub.");
    int interimProgressCount = 0;
    int displayProgressCount = 1000;
    int totalProgressCount = 0;

    // generate reference for list of new devices we're going to add, will write list to this blob
    BlobClient generateDevicesBlob = _blobContainerClient.GetBlobClient(_generateDevicesBlobName);

    // define serializedDevices as a generic list<string>
    var serializedDevices = new List<string>(numToAdd);

    for (int i = 1; i <= numToAdd; i++)
    {
        // Create device name with this format: Hub_00000000 + a new guid.
        // This should be large enough to display the largest number (1 million).
        string deviceName = $"Hub_{i:D8}_{Guid.NewGuid()}";
        Debug.Print($"Adding device '{deviceName}'");

        // Create a new ExportImportDevice.
        var deviceToAdd = new ExportImportDevice
        {
            Id = deviceName,
            Status = DeviceStatus.Enabled,
            Authentication = new AuthenticationMechanism
            {
                SymmetricKey = new SymmetricKey
                {
                    PrimaryKey = GenerateKey(32),
                    SecondaryKey = GenerateKey(32),
                }
            },
            // This indicates that the entry should be added as a new device.
            ImportMode = ImportMode.Create,
        };

        // Add device to the list as a serialized object.
        serializedDevices.Add(JsonConvert.SerializeObject(deviceToAdd));

        // Not real progress as you write the new devices, but will at least show *some* progress.
        interimProgressCount++;
        totalProgressCount++;
        if (interimProgressCount >= displayProgressCount)
        {
            Console.WriteLine($"Added {totalProgressCount}/{numToAdd} devices.");
            interimProgressCount = 0;
        }
    }

    // Now have a list of devices to be added, each one has been serialized.
    // Write the list to the blob.
    var sb = new StringBuilder();
    serializedDevices.ForEach(serializedDevice => sb.AppendLine(serializedDevice));

    // Write list of serialized objects to the blob.
    using Stream stream = await generateDevicesBlob.OpenWriteAsync(overwrite: true);
    byte[] bytes = Encoding.UTF8.GetBytes(sb.ToString());
    for (int i = 0; i < bytes.Length; i += BlobWriteBytes)
    {
        int length = Math.Min(bytes.Length - i, BlobWriteBytes);
        await stream.WriteAsync(bytes.AsMemory(i, length));
    }
    await stream.FlushAsync();

    Console.WriteLine("Running a registry manager job to add the devices.");

    // Should now have a file with all the new devices in it as serialized objects in blob storage.
    // generatedListBlob has the list of devices to be added as serialized objects.
    // Call import using the blob to add the new devices.
    // Log information related to the job is written to the same container.
    // This normally takes 1 minute per 100 devices (according to the docs).

    // First, initiate an import job.
    // This reads in the rows from the text file and writes them to IoT Devices.
    // If you want to add devices from a file, you can create a file and use this to import it.
    //   They have to be in the exact right format.
    try
    {
        // The first URI is the container to import from; the file defaults to devices.txt, but may be specified.
        // The second URI points to the container to write errors to as a blob.
        // This lets you import the devices from any file name. Since we wrote the new
        // devices to [devicesToAdd], need to read the list from there as well.
        var importGeneratedDevicesJob = JobProperties.CreateForImportJob(
            _containerUri,
            _containerUri,
            _generateDevicesBlobName);
        importGeneratedDevicesJob = await registryManager.ImportDevicesAsync(importGeneratedDevicesJob);
        await WaitForJobAsync(registryManager, importGeneratedDevicesJob);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Adding devices failed due to {ex.Message}");
    }

    stopwatch.Stop();
    Console.WriteLine($"GenerateDevices, time elapsed = {stopwatch.Elapsed}.");
}

Voorbeeld van het importeren van apparaten : bulksgewijs verwijderen

In het volgende C#-codefragment, uit de methode DeleteFromHubAsync in het SDK-voorbeeld, ziet u hoe u alle apparaten uit een IoT-hub verwijdert:

private async Task DeleteFromHubAsync(RegistryManager registryManager, bool includeConfigurations)
{
    var stopwatch = Stopwatch.StartNew();

    Console.WriteLine("Deleting all devices from an IoT hub.");

    Console.WriteLine("Exporting a list of devices from IoT hub to blob storage.");

    // Read from storage, which contains serialized objects.
    // Write each line to the serializedDevices list.
    BlobClient devicesBlobClient = _blobContainerClient.GetBlobClient(_destHubDevicesImportBlobName);

    Console.WriteLine("Reading the list of devices in from blob storage.");
    List<string> serializedDevices = await ReadFromBlobAsync(devicesBlobClient);

    // Step 1: Update each device's ImportMode to be Delete
    Console.WriteLine("Updating ImportMode to be 'Delete' for each device and writing back to the blob.");
    var sb = new StringBuilder();
    serializedDevices.ForEach(serializedEntity =>
    {
        // Deserialize back to an ExportImportDevice and change import mode.
        ExportImportDevice device = JsonConvert.DeserializeObject<ExportImportDevice>(serializedEntity);
        device.ImportMode = ImportMode.Delete;

        // Reserialize the object now that we've updated the property.
        sb.AppendLine(JsonConvert.SerializeObject(device));
    });

    // Step 2: Write the list in memory to the blob.
    BlobClient deleteDevicesBlobClient = _blobContainerClient.GetBlobClient(_hubDevicesCleanupBlobName);
    await WriteToBlobAsync(deleteDevicesBlobClient, sb.ToString());

    // Step 3: Call import using the same blob to delete all devices.
    Console.WriteLine("Running a registry manager job to delete the devices from the IoT hub.");
    var importJob = JobProperties.CreateForImportJob(
        _containerUri,
        _containerUri,
        _hubDevicesCleanupBlobName);
    importJob = await registryManager.ImportDevicesAsync(importJob);
    await WaitForJobAsync(registryManager, importJob);

    // Step 4: delete configurations
    if (includeConfigurations)
    {
        BlobClient configsBlobClient = _blobContainerClient.GetBlobClient(_srcHubConfigsExportBlobName);
        List<string> serializedConfigs = await ReadFromBlobAsync(configsBlobClient);
        foreach (string serializedConfig in serializedConfigs)
        {
            try
            {
                Configuration config = JsonConvert.DeserializeObject<Configuration>(serializedConfig);
                await registryManager.RemoveConfigurationAsync(config.Id);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to deserialize or remove a config.\n\t{serializedConfig}\n\n{ex.Message}");
            }
        }
    }

    stopwatch.Stop();
    Console.WriteLine($"Deleted IoT hub devices and configs: time elapsed = {stopwatch.Elapsed}");
}

De SAS-URI van de container ophalen

In het volgende codevoorbeeld ziet u hoe u een SAS-URI genereert met lees-, schrijf- en verwijdermachtigingen voor een blobcontainer:

static string GetContainerSasUri(CloudBlobContainer container)
{
  // Set the expiry time and permissions for the container.
  // In this case no start time is specified, so the
  // shared access signature becomes valid immediately.
  var sasConstraints = new SharedAccessBlobPolicy();
  sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
  sasConstraints.Permissions = 
    SharedAccessBlobPermissions.Write | 
    SharedAccessBlobPermissions.Read | 
    SharedAccessBlobPermissions.Delete;

  // Generate the shared access signature on the container,
  // setting the constraints directly on the signature.
  string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);

  // Return the URI string for the container,
  // including the SAS token.
  return container.Uri + sasContainerToken;
}

Volgende stappen

In dit artikel hebt u geleerd hoe u bulkbewerkingen uitvoert op het identiteitsregister in een IoT-hub. Veel van deze bewerkingen, waaronder het verplaatsen van apparaten van de ene hub naar de andere, worden gebruikt in de sectie Apparaten beheren die zijn geregistreerd bij de IoT-hub van Het handmatig migreren van een Azure IoT-hub met behulp van een Azure Resource Manager-sjabloon.