| File: TenantScopedResourceAnnotation.cs | Web Access |
| Project: src\src\Aspire.Hosting.Azure\Aspire.Hosting.Azure.csproj (Aspire.Hosting.Azure) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Azure; /// <summary> /// Identifies a Bicep module that creates tenant-scoped resources outside Azure Resource Manager. /// </summary> /// <remarks> /// This annotation describes the created resources, not the ARM deployment scope. Annotated resources participate /// in tenant resource suffix configuration. Provisioning, deployment cancellation, and local state management /// remain available, but ARM resource inspection, relocation, deletion, and drift probes do not apply. /// Resource-group deletion leaves these resources and their cached identification outputs intact, and reports /// them for provider-specific cleanup. /// </remarks> [Experimental("ASPIREAZURE003", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] public sealed class TenantScopedResourceAnnotation : IResourceAnnotation { /// <summary> /// Initializes an annotation describing the tenant-scoped objects created by a module. /// </summary> /// <param name="resourceIdOutputs"> /// A mapping from provider resource types to Bicep output names containing their object IDs. /// Only non-secret identification outputs should be included because they are reported in deletion results. /// </param> /// <exception cref="ArgumentNullException">Thrown when <paramref name="resourceIdOutputs"/> is null.</exception> /// <exception cref="ArgumentException">Thrown when a resource type or output name is empty.</exception> /// <example> /// <code lang="csharp"> /// resource.Annotations.Add(new TenantScopedResourceAnnotation(new Dictionary<string, string> /// { /// ["Microsoft.Graph/applications"] = "objectId", /// ["Microsoft.Graph/servicePrincipals"] = "servicePrincipalId" /// })); /// </code> /// </example> public TenantScopedResourceAnnotation(IReadOnlyDictionary<string, string> resourceIdOutputs) { ArgumentNullException.ThrowIfNull(resourceIdOutputs); var outputs = new Dictionary<string, string>(StringComparer.Ordinal); foreach (var (resourceType, outputName) in resourceIdOutputs) { ArgumentException.ThrowIfNullOrWhiteSpace(resourceType); ArgumentException.ThrowIfNullOrWhiteSpace(outputName); outputs.Add(resourceType, outputName); } ResourceIdOutputs = new ReadOnlyDictionary<string, string>(outputs); } /// <summary> /// Gets the provider resource types and the output names used to identify objects left after resource-group deletion. /// </summary> public IReadOnlyDictionary<string, string> ResourceIdOutputs { get; } }