Microsoft Azure Resource Manager-Clientbibliothek für .NET
Microsoft Azure Resource Manager ist der Bereitstellungs- und Verwaltungsdienst für Azure. Er bietet eine Verwaltungsebene, die das Erstellen, Aktualisieren und Löschen von Ressourcen in Ihrem Azure-Konto ermöglicht.
Diese Bibliothek bietet Ressourcengruppen- und Ressourcenverwaltungsfunktionen für Microsoft Azure.
Diese Bibliothek folgt den neuen Azure SDK-Richtlinien und bietet viele Kernfunktionen:
- 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.
Erste Schritte
Installieren des Pakets
Installieren Sie die Microsoft Azure Resources Management Core-Bibliothek für .NET mit NuGet:
dotnet add package Azure.ResourceManager
Voraussetzungen
Sie benötigen ein Microsoft Azure-Abonnement.
Einrichten einer Möglichkeit zum Authentifizieren bei Azure mit Azure Identity.
Unter anderem gibt es folgende Optionen:
- Melden Sie sich über die Azure CLI an.
- Über Visual Studio.
- Festlegen von Umgebungsvariablen.
Weitere Informationen und verschiedene Authentifizierungsansätze mit Azure Identity finden Sie in diesem Dokument.
Authentifizieren des Clients
Die Standardoption zum Erstellen eines authentifizierten Clients ist die Verwendung von DefaultAzureCredential
. Da alle Verwaltungs-APIs denselben Endpunkt verwenden, muss nur eine oberste Ebene ArmClient
erstellt werden, um mit Ressourcen zu interagieren.
Führen Sie den folgenden Code aus, um sich bei Azure zu authentifizieren und eine ArmClient
zu erstellen:
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());
Weitere Dokumentation für die Azure.Identity.DefaultAzureCredential
Klasse finden Sie in diesem Dokument.
Wichtige Begriffe
Grundlegendes zur Azure-Ressourcenhierarchie
Um sowohl die Anzahl der Clients zu reduzieren, die zum Ausführen allgemeiner Aufgaben erforderlich sind, als auch die Anzahl redundanter Parameter, die jeder dieser Clients verwendet, haben wir eine Objekthierarchie im SDK eingeführt, die die Objekthierarchie in Azure imitiert. Jeder Ressourcenclient im SDK verfügt über Methoden für den Zugriff auf die Ressourcenclients der ihm untergeordneten Elemente, die bereits dem richtigen Abonnement und der richtigen Ressourcengruppe angepasst sind.
Um dieses Ziel zu erreichen, führen wir drei Standardtypen für alle Ressourcen in Azure ein:
[Ressource] Resource.cs
Diese Klasse stellt ein vollständiges Ressourcenclientobjekt dar, das eine Data-Eigenschaft enthält, die die Details als [Resource]Datentyp verfügbar macht. Es hat auch Zugriff auf alle Vorgänge für diese Ressource, ohne Bereichsparameter wie die Abonnement-ID oder den Ressourcennamen übergeben zu müssen. Diese Ressourcenklasse macht es bequem, Vorgänge direkt nach dem Ergebnis von Listenaufrufen auszuführen, da jetzt alles als vollständiger Ressourcenclient zurückgegeben wird.
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
Diese Klasse stellt das Modell dar, aus dem eine bestimmte Ressource besteht. In der Regel handelt es sich bei dieser Klasse um die Antwortdaten eines Dienstaufrufs, z. B. HTTP GET, und sie stellt Details zur zugrunde liegenden Ressource bereit. Bisher wurde diese Klasse durch eine Model-Klasse dargestellt.
[Resource]Collection.cs
Diese Klasse stellt die Vorgänge dar, die Sie für eine Sammlung von Ressourcen ausführen können, die zu einer bestimmten übergeordneten Ressource gehören. Diese Klasse stellt die meisten logischen Auflistungsvorgänge bereit.
Sammlungsverhalten | Sammlungsmethode |
---|---|
Iterieren/Auflisten | GetAll() |
Index | Get(Zeichenfolgenname) |
Hinzufügen | CreateOrUpdate(Zeichenfolgenname, [Resource]Data data) |
Enthält | Exists(Zeichenfolgenname) |
In den meisten Fällen ist das übergeordnete Element eine ResourceGroup. Beispielsweise ist ein Subnet ein untergeordnetes Element eines VirtualNetwork und eine ResourceGroup ein untergeordnetes Element einer Subscription.
Zusammenfügen des Gesamtbilds
Stellen Sie sich vor, dass unser Unternehmen verlangt, dass alle virtuellen Computer mit dem Besitzer gekennzeichnet werden. Wir haben die Aufgabe, ein Programm zu schreiben, um das Tag allen fehlenden virtuellen Computern in einer bestimmten Ressourcengruppe hinzuzufügen.
// 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");
}
}
Strukturierter Ressourcenbezeichner
Ressourcen-IDs enthalten nützliche Informationen zur Ressource selbst, sind jedoch einfache Zeichenfolgen, die analysiert werden müssen. Anstatt Eine eigene Analyselogik zu implementieren, können Sie ein ResourceIdentifier
-Objekt verwenden, das die Analyse für Sie übernimmt: new ResourceIdentifier("myid");
.
Beispiel: Analyse einer ID mithilfe eines ResourceIdentifier-Objekts
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}");
Verwalten vorhandener Ressourcen nach Ressourcenbezeichner
Das Ausführen von Vorgängen für bereits vorhandene Ressourcen ist ein häufiger Anwendungsfall bei Verwendung der Verwaltungsclientbibliotheken. In diesem Szenario verfügen Sie in der Regel in Form einer Zeichenfolge über den Bezeichner der Ressource, an der Sie arbeiten möchten. Obwohl sich die neue Objekthierarchie hervorragend für die Bereitstellung eignet und innerhalb des Bereichs eines bestimmten übergeordneten Elements funktioniert, ist sie in diesem spezifischen Szenario nicht die effizienteste.
Hier sehen Sie ein Beispiel, wie Sie auf ein AvailabilitySet
Objekt zugreifen und es direkt mit seiner ID verwalten können:
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);
Dieser Ansatz erforderte viel Code und drei API-Aufrufe an Azure. Dasselbe kann mit weniger Code und ohne API-Aufrufe mithilfe von Erweiterungsmethoden erfolgen, die wir auf dem Client selbst bereitgestellt haben. Mit diesen Erweiterungsmethoden können Sie einen Ressourcenbezeichner übergeben und einen bereichsbezogenen Ressourcenclient abrufen. Bei dem zurückgegebenen Objekt handelt es sich um eine [Ressource], die oben erwähnt wurde, da es sich nicht an Azure geholt hat, um die Daten abzurufen, aber die Data-Eigenschaft ist NULL.
Das vorherige Beispiel würde daher folgendermaßen aussehen:
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);
Wir bieten auch eine Option, die, wenn Sie nur die Teile kennen, aus denen die ResourceIdentifier
einzelnen Ressourcen bestehen, eine statische Methode zum Erstellen der vollständigen Zeichenfolge aus diesen Teilen bereitstellt.
Das obige Beispiel würde dann wie folgt aussehen.
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);
Überprüfen, ob eine [Resource] vorhanden ist
Wenn Sie nicht sicher sind, ob eine Ressource vorhanden ist, die Sie abrufen möchten, oder wenn Sie nur überprüfen möchten, ob sie vorhanden ist, können Sie die -Methode verwenden Exists()
, die von jeder [Resource]Collection-Klasse aufgerufen werden kann.
Exists()
und ExistsAsync()
gibt zurück Response<bool>
, wenn die angegebene Ressource nicht vorhanden ist. Beide Methoden bieten Ihnen weiterhin Zugriff auf die zugrunde liegende Rohantwort.
Bevor diese Methoden eingeführt wurden, müssen Sie die abfangen und den RequestFailedException
status Code für 404 untersuchen.
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.");
}
Mit diesen praktischen Methoden können wir nun den folgenden Code ausführen.
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.");
}
Beispiele
Erstellen einer Ressourcengruppe
// 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;
Auflisten aller Ressourcengruppen
// 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);
}
Aktualisieren einer Ressourcengruppe
// 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");
Löschen einer Ressourcengruppe
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);
Abrufen der GenericResource-Liste
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");
Erstellen von 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");
Aktualisieren von 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");
Aktualisieren von GenericResourc-Tags
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");
Abrufen von 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");
Überprüfen, ob GenericResource vorhanden ist
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}");
Löschen von 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}");
Ausführlichere Beispiele finden Sie in den verfügbaren Beispielen.
Azure Resource Manager-Tests
So führen Sie den Test aus: dotnet test
So führen Sie einen Test mit Code Coverage aus und generieren automatisch einen HTML-Bericht: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
Der Abdeckungsbericht wird in Ihrem Pfad relativ zu azure-proto-core-test im/coverage
HTML-Format zur Anzeige platziert.
Berichte können auch vs oder VsCode mit dem richtigen Viewer-Plug-In angezeigt werden.
Ein terse-Bericht wird auch in der Befehlszeile angezeigt, wenn sie ausgeführt wird.
Ausführen eines Tests mit einer einzelnen Datei oder einem Test
So führen Sie einen Test mit Code Coverage aus und generieren automatisch einen HTML-Bericht mit nur einem einzigen Test: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --filter <test-to-run>
Problembehandlung
- Melden Sie ein Problem über GitHub Issues.
- Überprüfen Sie vorherige Fragen , oder stellen Sie neue Fragen in Stack Overflow mithilfe von Azure- und .NET-Tags.
Nächste Schritte
Weiterer Beispielcode
- Verwalten von Ressourcengruppen
- Erstellen eines virtuellen Netzwerks
- Codebeispiele für die .NET-Verwaltungsbibliothek
Weitere Dokumentation
Wenn Sie aus dem alten SDK migrieren, lesen Sie diesen Migrationsleitfaden.
Weitere Informationen zum Microsoft Azure SDK finden Sie auf dieser Website.
Mitwirken
Ausführliche Informationen zum Mitwirken zu diesem Repository finden Sie im Leitfaden zur Mitarbeit.
Beiträge und Vorschläge für dieses Projekt sind willkommen. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. Ausführliche Informationen finden Sie unter https://cla.microsoft.com.
Wenn Sie einen Pull Request übermitteln, bestimmt ein CLA-Bot automatisch, ob Sie eine CLA bereitstellen und den PR entsprechend dekorieren müssen (z. B. Bezeichnung, Kommentar). Folgen Sie den Anweisungen des Bots. Sie müssen diese Aktion nur einmal für alle Repositorys mit unserer CLA ausführen.
Für dieses Projekt gelten die Microsoft-Verhaltensregeln für Open Source (Microsoft Open Source Code of Conduct). Weitere Informationen finden Sie in den häufig gestellten Fragen zum Verhaltenskodex. Sie können sich auch an opencode@microsoft.com wenden, wenn Sie weitere Fragen oder Anmerkungen haben.