Compartir a través de


Biblioteca cliente de Microsoft Azure Resource Manager para .NET

Microsoft Azure Resource Manager es el servicio de implementación y administración para Azure. Proporciona una capa de administración que le permite crear, actualizar y eliminar recursos de la cuenta de Azure.

Esta biblioteca proporciona funcionalidades de administración de recursos y grupos de recursos para Microsoft Azure.

Esta biblioteca sigue las nuevas directrices del SDK de Azure y proporciona muchas funcionalidades principales:

- Support MSAL.NET, Azure.Identity is out of box for supporting MSAL.NET.
- Support [OpenTelemetry](https://opentelemetry.io/) for distributed tracing.
- HTTP pipeline with custom policies.
- Better error-handling.
- Support uniform telemetry across all languages.

Introducción

Instalar el paquete

Instale la biblioteca principal de administración de recursos de Microsoft Azure para .NET con NuGet:

dotnet add package Azure.ResourceManager

Requisitos previos

Autenticar el cliente

La opción predeterminada para crear un cliente autenticado es usar DefaultAzureCredential. Dado que todas las API de administración pasan por el mismo punto de conexión, para interactuar con los recursos, solo se tiene que crear un ArmClient de nivel superior.

Para autenticarse en Azure y crear un ArmClient, realice el código siguiente:

using System;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Compute;
using Azure.ResourceManager.Resources;
ArmClient client = new ArmClient(new DefaultAzureCredential());

Puede encontrar más documentación para la Azure.Identity.DefaultAzureCredential clase en este documento.

Conceptos clave

Descripción de la jerarquía de recursos de Azure

Para reducir el número de clientes necesarios para realizar tareas comunes y el número de parámetros redundantes que toman cada uno de esos clientes, hemos introducido una jerarquía de objetos en el SDK que imita la jerarquía de objetos en Azure. Cada cliente de recursos del SDK tiene métodos para acceder a los clientes de recursos de sus elementos secundarios, que ya está limitado a la suscripción y el grupo de recursos adecuados.

Para lograr este objetivo, vamos a introducir tres tipos estándar para todos los recursos de Azure:

[Recurso] Resource.cs

Esta clase representa un objeto de cliente de recursos completo que contiene una propiedad Data que expone los detalles como un tipo de datos [Resource] . También tiene acceso a todas las operaciones de ese recurso sin necesidad de pasar parámetros de ámbito, como el identificador de suscripción o el nombre del recurso. Esta clase de recursos facilita la ejecución directa de operaciones en el resultado de las llamadas de lista, ya que todo se devuelve como un cliente de recursos completo ahora.

ArmClient client = new ArmClient(new DefaultAzureCredential());
string resourceGroupName = "myResourceGroup";
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
await foreach (VirtualMachineResource virtualMachine in resourceGroup.GetVirtualMachines())
{
    //previously we would have to take the resourceGroupName and the vmName from the vm object
    //and pass those into the powerOff method as well as we would need to execute that on a separate compute client
    await virtualMachine.PowerOffAsync(WaitUntil.Completed);
}

[Resource]Data.cs

Esta clase representa el modelo que constituye un recurso determinado. Normalmente, esta clase es los datos de respuesta de una llamada de servicio como HTTP GET y proporciona detalles sobre el recurso subyacente. Anteriormente, esta clase estaba representada por una clase Model .

[Resource]Collection.cs

Esta clase representa las operaciones que puede realizar en una colección de recursos que pertenecen a un recurso primario específico. Esta clase proporciona la mayoría de las operaciones de colección lógica.

Comportamiento de la colección Método de la colección
Iteración/Lista GetAll()
Índice Get(nombre_de_cadena)
Sumar CreateOrUpdate(nombre_de_cadena, [Resource]Data data)
Contiene Existe (nombre de cadena)

En la mayoría de los casos, el elemento primario será una clase ResourceGroup. Por ejemplo, Subnet es un elemento secundario de VirtualNetwork y ResourceGroup es un elemento secundario de Subscription.

Resumen

Imagine que nuestra empresa necesita que todas las máquinas virtuales se etiqueten con el propietario. Se nos encomienda escribir un programa para agregar la etiqueta a las máquinas virtuales que faltan en un grupo de recursos determinado.

// First we construct our client
ArmClient client = new ArmClient(new DefaultAzureCredential());

// Next we get a resource group object
// ResourceGroupResource is a [Resource] object from above
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync("myRgName");

// Next we get the collection for the virtual machines
// vmCollection is a [Resource]Collection object from above
VirtualMachineCollection virtualMachines = resourceGroup.GetVirtualMachines();

// Next we loop over all vms in the collection
// Each vm is a [Resource] object from above
await foreach (VirtualMachineResource virtualMachine in virtualMachines)
{
   // We access the [Resource]Data properties from vm.Data
   if (!virtualMachine.Data.Tags.ContainsKey("owner"))
   {
       // We can also access all operations from vm since it is already scoped for us
       await virtualMachine.AddTagAsync("owner", "tagValue");
   }
}

Identificador de recursos estructurado

Los id. de recurso contienen información útil sobre el propio recurso, pero son cadenas sin formato que se deben analizar. En lugar de implementar lógica de análisis propia, puede usar un objeto ResourceIdentifier que realizará el análisis de forma automática: new ResourceIdentifier("myid");.

Ejemplo: Análisis de un identificador mediante un objeto ResourceIdentifier

ResourceIdentifier id = new ResourceIdentifier("/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/workshop2021-rg/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/mySubnet");
Console.WriteLine($"Subscription: {id.SubscriptionId}");
Console.WriteLine($"ResourceGroupResource: {id.ResourceGroupName}");
Console.WriteLine($"Vnet: {id.Parent.Name}");
Console.WriteLine($"Subnet: {id.Name}");

Administración de recursos existentes por identificador de recursos

La realización de operaciones en recursos que ya existen es un caso de uso común al usar las bibliotecas cliente de administración. En este escenario, normalmente tiene en forma de cadena el identificador del recurso en el que quiere trabajar. Aunque la nueva jerarquía de objetos es excelente para el aprovisionamiento y trabajar dentro del ámbito de un elemento primario determinado, no es la más eficaz cuando se trata de este escenario específico.

Este es un ejemplo de cómo puede acceder a un AvailabilitySet objeto y administrarlo directamente con su identificador:

ResourceIdentifier id = new ResourceIdentifier("/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/workshop2021-rg/providers/Microsoft.Compute/availabilitySets/ws2021availSet");
// We construct a new client to work with
ArmClient client = new ArmClient(new DefaultAzureCredential());
// Next we get the collection of subscriptions
SubscriptionCollection subscriptions = client.GetSubscriptions();
// Next we get the specific subscription this resource belongs to
SubscriptionResource subscription = await subscriptions.GetAsync(id.SubscriptionId);
// Next we get the collection of resource groups that belong to that subscription
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
// Next we get the specific resource group this resource belongs to
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(id.ResourceGroupName);
// Next we get the collection of availability sets that belong to that resource group
AvailabilitySetCollection availabilitySets = resourceGroup.GetAvailabilitySets();
// Finally we get the resource itself
// Note: for this last step in this example, Azure.ResourceManager.Compute is needed
AvailabilitySetResource availabilitySet = await availabilitySets.GetAsync(id.Name);

Este enfoque requiere mucho código y tres llamadas API a Azure. Lo mismo se puede hacer con menos código y sin ninguna llamada API, mediante los métodos de extensión que hemos proporcionado en el propio cliente. Estos métodos de extensión permiten pasar un identificador de recurso y recuperar un cliente de recurso con ámbito. El objeto devuelto es un [Recurso] mencionado anteriormente, ya que no se ha llegado a Azure para recuperar los datos, pero la propiedad Data será null.

Por tanto, el ejemplo anterior terminaría con este aspecto:

ResourceIdentifier resourceId = new ResourceIdentifier("/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/workshop2021-rg/providers/Microsoft.Compute/availabilitySets/ws2021availSet");
// We construct a new client to work with
ArmClient client = new ArmClient(new DefaultAzureCredential());
// Next we get the AvailabilitySetResource resource client from the client
// The method takes in a ResourceIdentifier but we can use the implicit cast from string
AvailabilitySetResource availabilitySet = client.GetAvailabilitySetResource(resourceId);
// At this point availabilitySet.Data will be null and trying to access it will throw
// If we want to retrieve the objects data we can simply call get
availabilitySet = await availabilitySet.GetAsync();
// we now have the data representing the availabilitySet
Console.WriteLine(availabilitySet.Data.Name);

También proporcionamos una opción que si solo conoce las partes que componen cada ResourceIdentifier recurso proporciona un método estático para construir la cadena completa a partir de esas piezas. A continuación, el ejemplo anterior tendría este aspecto.

string subscriptionId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
string resourceGroupName = "workshop2021-rg";
string availabilitySetName = "ws2021availSet";
ResourceIdentifier resourceId = AvailabilitySetResource.CreateResourceIdentifier(subscriptionId, resourceGroupName, availabilitySetName);
// We construct a new client to work with
ArmClient client = new ArmClient(new DefaultAzureCredential());
// Next we get the AvailabilitySetResource resource client from the client
// The method takes in a ResourceIdentifier but we can use the implicit cast from string
AvailabilitySetResource availabilitySet = client.GetAvailabilitySetResource(resourceId);
// At this point availabilitySet.Data will be null and trying to access it will throw
// If we want to retrieve the objects data we can simply call get
availabilitySet = await availabilitySet.GetAsync();
// we now have the data representing the availabilitySet
Console.WriteLine(availabilitySet.Data.Name);

Comprobación de la existencia de [Resource]

Si no está seguro de si existe un recurso que desea obtener, o simplemente desea comprobar si existe, puede usar Exists() el método , que se puede invocar desde cualquier clase [Resource]Collection.

Exists() y ExistsAsync() devuelven Response<bool> donde la bool será false si el recurso especificado no existe. Los dos métodos todavía permiten acceder a la respuesta subyacente sin procesar.

Antes de introducir estos métodos, tendría que detectar e RequestFailedException inspeccionar el código de estado para 404.

ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
string resourceGroupName = "myRgName";

try
{
    ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
    // At this point, we are sure that myRG is a not null Resource Group, so we can use this object to perform any operations we want.
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
    Console.WriteLine($"Resource Group {resourceGroupName} does not exist.");
}

Ahora con estos métodos de conveniencia podemos hacer el código siguiente.

ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
string resourceGroupName = "myRgName";

bool exists = await resourceGroups.ExistsAsync(resourceGroupName);

if (exists)
{
    Console.WriteLine($"Resource Group {resourceGroupName} exists.");

    // We can get the resource group now that we know it exists.
    // This does introduce a small race condition where resource group could have been deleted between the check and the get.
    ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
}
else
{
    Console.WriteLine($"Resource Group {resourceGroupName} does not exist.");
}

Ejemplos

Crear un grupo de recursos

// First, initialize the ArmClient and get the default subscription
ArmClient client = new ArmClient(new DefaultAzureCredential());
// Now we get a ResourceGroupResource collection for that subscription
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();

// With the collection, we can create a new resource group with an specific name
string resourceGroupName = "myRgName";
AzureLocation location = AzureLocation.WestUS2;
ResourceGroupData resourceGroupData = new ResourceGroupData(location);
ArmOperation<ResourceGroupResource> operation = await resourceGroups.CreateOrUpdateAsync(WaitUntil.Completed, resourceGroupName, resourceGroupData);
ResourceGroupResource resourceGroup = operation.Value;

Enumerar todos los grupos de recursos

// First, initialize the ArmClient and get the default subscription
ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
// Now we get a ResourceGroupResource collection for that subscription
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
// We can then iterate over this collection to get the resources in the collection
await foreach (ResourceGroupResource resourceGroup in resourceGroups)
{
    Console.WriteLine(resourceGroup.Data.Name);
}

Actualizar un grupo de recursos

// Note: Resource group named 'myRgName' should exist for this example to work.
ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
string resourceGroupName = "myRgName";
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
resourceGroup = await resourceGroup.AddTagAsync("key", "value");

Eliminación de un grupo de recursos

ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
string resourceGroupName = "myRgName";
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
await resourceGroup.DeleteAsync(WaitUntil.Completed);

Obtener lista GenericResource

ArmClient client = new ArmClient(new DefaultAzureCredential());
SubscriptionResource sub = client.GetDefaultSubscription();
AsyncPageable<GenericResource> networkAndVmWithTestInName = sub.GetGenericResourcesAsync(
    // Set filter to only return virtual network and virtual machine resource with 'test' in the name
    filter: "(resourceType eq 'Microsoft.Network/virtualNetworks' or resourceType eq 'Microsoft.Compute/virtualMachines') and substringof('test', name)",
    // Include 'createdTime' and 'changeTime' properties in the returned data
    expand: "createdTime,changedTime"
    );

int count = 0;
await foreach (var res in networkAndVmWithTestInName)
{
    Console.WriteLine($"{res.Id.Name} in resource group {res.Id.ResourceGroupName} created at {res.Data.CreatedOn} and changed at {res.Data.ChangedOn}");
    count++;
}
Console.WriteLine($"{count} resources found");

Creación de GenericResource

ArmClient client = new ArmClient(new DefaultAzureCredential());

var subnetName = "samplesubnet";
var addressSpaces = new Dictionary<string, object>()
{
    { "addressPrefixes", new List<string>() { "10.0.0.0/16" } }
};
var subnet = new Dictionary<string, object>()
{
    { "name", subnetName },
    { "properties", new Dictionary<string, object>()
        {
            { "addressPrefix", "10.0.1.0/24" }
        }
    }
};
var subnets = new List<object>() { subnet };
var data = new GenericResourceData(AzureLocation.EastUS)
{
    Properties = BinaryData.FromObjectAsJson(new Dictionary<string, object>()
    {
        { "addressSpace", addressSpaces },
        { "subnets", subnets }
    })
};
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");

var createResult = await client.GetGenericResources().CreateOrUpdateAsync(WaitUntil.Completed, id, data);
Console.WriteLine($"Resource {createResult.Value.Id.Name} in resource group {createResult.Value.Id.ResourceGroupName} created");

Actualizar GenericResource

ArmClient client = new ArmClient(new DefaultAzureCredential());

var subnetName = "samplesubnet";
var addressSpaces = new Dictionary<string, object>()
{
    { "addressPrefixes", new List<string>() { "10.0.0.0/16" } }
};
var subnet = new Dictionary<string, object>()
{
    { "name", subnetName },
    { "properties", new Dictionary<string, object>()
        {
            { "addressPrefix", "10.0.1.0/24" }
        }
    }
};
var subnets = new List<object>() { subnet };
var data = new GenericResourceData(AzureLocation.EastUS)
{
    Properties = BinaryData.FromObjectAsJson(new Dictionary<string, object>()
    {
        { "addressSpace", addressSpaces },
        { "subnets", subnets }
    })
};
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");

var createResult = await client.GetGenericResources().CreateOrUpdateAsync(WaitUntil.Completed, id, data);
Console.WriteLine($"Resource {createResult.Value.Id.Name} in resource group {createResult.Value.Id.ResourceGroupName} updated");

Actualizar etiquetas GenericResourc

ArmClient client = new ArmClient(new DefaultAzureCredential());
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");
GenericResource resource = client.GetGenericResources().Get(id).Value;

GenericResourceData updateTag = new GenericResourceData(AzureLocation.EastUS);
updateTag.Tags.Add("tag1", "sample-for-genericresource");
ArmOperation<GenericResource> updateTagResult = await resource.UpdateAsync(WaitUntil.Completed, updateTag);

Console.WriteLine($"Resource {updateTagResult.Value.Id.Name} in resource group {updateTagResult.Value.Id.ResourceGroupName} updated");

Obtener GenericResource

ArmClient client = new ArmClient(new DefaultAzureCredential());
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");

Response<GenericResource> getResultFromGenericResourceCollection = await client.GetGenericResources().GetAsync(id);
Console.WriteLine($"Resource {getResultFromGenericResourceCollection.Value.Id.Name} in resource group {getResultFromGenericResourceCollection.Value.Id.ResourceGroupName} got");

GenericResource resource = getResultFromGenericResourceCollection.Value;
Response<GenericResource> getResultFromGenericResource = await resource.GetAsync();
Console.WriteLine($"Resource {getResultFromGenericResource.Value.Id.Name} in resource group {getResultFromGenericResource.Value.Id.ResourceGroupName} got");

Comprobación de si GenericResource existe

ArmClient client = new ArmClient(new DefaultAzureCredential());
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");

bool existResult = await client.GetGenericResources().ExistsAsync(id);
Console.WriteLine($"Resource exists: {existResult}");

Eliminar GenericResource

ArmClient client = new ArmClient(new DefaultAzureCredential());
ResourceIdentifier id = new ResourceIdentifier("/subscriptions/{subscription_id}/resourceGroups/{resourcegroup_name}/providers/Microsoft.Network/virtualNetworks/{vnet_name}");
GenericResource resource = client.GetGenericResources().Get(id).Value;

var deleteResult = await resource.DeleteAsync(WaitUntil.Completed);
Console.WriteLine($"Resource deletion response status code: {deleteResult.WaitForCompletionResponse().Status}");

Para obtener ejemplos más detallados, vea los ejemplos disponibles.

Pruebas de Azure Resource Manager

Para ejecutar la prueba: dotnet test

Para ejecutar pruebas con cobertura de código y generar automáticamente un informe html: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura

El informe de cobertura se colocará en la ruta de acceso relativa a azure-proto-core-test en/coverage formato html para su visualización.

Los informes también se pueden ver en VS o VsCode con el complemento de visor adecuado.

También se mostrará un informe terse en la línea de comandos al ejecutarse.

Ejecutar prueba con un único archivo o prueba

Para ejecutar pruebas con cobertura de código y generar automáticamente un informe html con una sola prueba: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --filter <test-to-run>

Solución de problemas

Pasos siguientes

Más código de ejemplo

Otra documentación

Si va a migrar desde el SDK anterior, consulte esta guía de migración.

Para más información sobre el SDK de Microsoft Azure, consulte este sitio web.

Contribuciones

Para más información sobre cómo contribuir a este repositorio, consulte la guía de contribución.

Este proyecto agradece las contribuciones y sugerencias. La mayoría de las contribuciones requieren que acepte un Contrato de licencia para el colaborador (CLA) que declara que tiene el derecho a concedernos y nos concede los derechos para usar su contribución. Para más detalles, visite https://cla.microsoft.com.

Al enviar una solicitud de incorporación de cambios, un bot de CLA determinará automáticamente si necesita proporcionar un CLA y decorar la solicitud de incorporación de cambios correctamente (por ejemplo, etiqueta, comentario). Siga las instrucciones que le dará el bot. Solo tendrá que realizar esta acción una vez en todos los repositorios mediante nuestro CLA.

El proyecto ha adoptado el Código de conducta de código abierto de Microsoft. Para más información, consulte las preguntas frecuentes del código de conducta o escriba un correo electrónico a opencode@microsoft.com si tiene cualquier otra pregunta o comentario.