| File: RadiusBackingResourceProjectionException.cs | Web Access |
| Project: src\src\Aspire.Hosting.Radius\Aspire.Hosting.Radius.csproj (Aspire.Hosting.Radius) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Radius; /// <summary> /// Thrown when a Radius <em>backing</em> resource — a cache, database, or queue provisioned by a /// Radius recipe rather than deployed as a <c>Radius.Compute/containers</c> workload — cannot be /// projected to its consumers: its address cannot be determined, or the recipe's own connection /// and credential outputs cannot be described. /// </summary> /// <remarks> /// <para> /// A backing resource's Kubernetes objects and credentials are created by its recipe, so no value /// derived from the Aspire endpoint model describes it. The Radius publisher projects the address /// out of the recipe's own outputs instead. Every other route to that address — including /// <see cref="RadiusEnvironmentResource.GetHostAddressExpression(EndpointReference)"/> and the /// cross-environment endpoint resolution other compute publishers use — would have to guess, so it /// throws this exception rather than emitting an address that silently resolves to nothing. See /// <see href="https://github.com/microsoft/aspire/issues/18935"/>. /// </para> /// <para> /// This type is public because it can surface from a Kubernetes, Azure Container Apps, or Azure /// App Service publish: those publishers resolve a cross-environment reference through the Radius /// environment that owns the resource. Catching it requires a type an AppHost author can name. /// </para> /// <para> /// It derives from <see cref="InvalidOperationException"/> to match the package's publish-time /// failure convention. Note that /// <c>AzureAppServiceEnvironmentResource</c>'s validation pass catches /// <see cref="InvalidOperationException"/> around its context lookup; that catch does not cover /// environment-variable resolution, so this exception is not swallowed there. /// </para> /// </remarks> /// <example> /// Deploying the consumer and the backing resource to the same Radius environment resolves the /// address case. An AppHost that publishes several environments can report the offending resource: /// <code language="csharp"> /// try /// { /// await app.RunAsync(); /// } /// catch (RadiusBackingResourceProjectionException ex) /// { /// Console.Error.WriteLine($"'{ex.Resource.Name}' is provisioned by a Radius recipe and cannot " + /// $"be projected to its consumers: {ex.Message}"); /// } /// </code> /// </example> public sealed class RadiusBackingResourceProjectionException : InvalidOperationException { /// <summary> /// Initializes a new instance of the <see cref="RadiusBackingResourceProjectionException"/> class. /// </summary> /// <param name="resource">The backing resource that could not be projected.</param> /// <param name="message">The message that describes the error.</param> /// <exception cref="ArgumentNullException"><paramref name="resource"/> is <see langword="null"/>.</exception> public RadiusBackingResourceProjectionException(IResource resource, string message) : this(resource, message, innerException: null) { } /// <summary> /// Initializes a new instance of the <see cref="RadiusBackingResourceProjectionException"/> class /// with a reference to the inner exception that is the cause of this exception. /// </summary> /// <param name="resource">The backing resource that could not be projected.</param> /// <param name="message">The message that describes the error.</param> /// <param name="innerException">The exception that is the cause of this exception, or /// <see langword="null"/> when none.</param> /// <remarks> /// The parameterless and message-only constructors that <see cref="InvalidOperationException"/> /// offers are deliberately not exposed: <see cref="Resource"/> is part of this type's contract — /// a caller catching it does so to report which resource failed — and an instance without one /// could not answer that. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="resource"/> is <see langword="null"/>.</exception> public RadiusBackingResourceProjectionException(IResource resource, string message, Exception? innerException) : base(message, innerException) { ArgumentNullException.ThrowIfNull(resource); Resource = resource; } /// <summary> /// Gets the backing resource that could not be projected. /// </summary> public IResource Resource { get; } }