| File: RedisResource.cs | Web Access |
| Project: src\src\Aspire.Hosting.Redis\Aspire.Hosting.Redis.csproj (Aspire.Hosting.Redis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable ASPIRECONTAINERSHELLEXECUTION001 namespace Aspire.Hosting.ApplicationModel; /// <summary> /// A resource that represents a Redis resource independent of the hosting model. /// </summary> /// <remarks> /// A resource that represents a Redis resource independent of the hosting model. /// </remarks> /// <param name="name">The name of the resource.</param> [AspireExport(ExposeProperties = true)] public class RedisResource(string name) : ContainerResource(name), IResourceWithConnectionString { /// <summary> /// Initializes a new instance of the <see cref="RedisResource"/> class. /// </summary> /// <param name="name">The name of the resource.</param> /// <param name="password">A parameter that contains the Redis server password.</param> public RedisResource(string name, ParameterResource password) : this(name) { PasswordParameter = password; ShellExecution = true; } internal const string PrimaryEndpointName = "tcp"; // The non-TLS endpoint if TLS is enabled, otherwise not allocated internal const string SecondaryEndpointName = "secondary"; /// <summary> /// The standard URI scheme registered for Redis, similar to http. See: https://github.com/redis/redis-specifications/blob/1252427cdbc497f66a7f8550c6b5f2f35367dc92/uri/redis.txt /// </summary> internal const string StandardRedisScheme = "redis"; /// <summary> /// The TLS URI scheme registered for Redis, similar to https. See: https://github.com/redis/redis-specifications/blob/1252427cdbc497f66a7f8550c6b5f2f35367dc92/uri/rediss.txt /// </summary> internal const string TlsRedisScheme = "rediss"; private EndpointReference? _primaryEndpoint; /// <summary> /// Gets the primary endpoint for the Redis server. /// </summary> public EndpointReference PrimaryEndpoint => _primaryEndpoint ??= new(this, PrimaryEndpointName); /// <summary> /// Gets the host endpoint reference for this resource. /// </summary> public EndpointReferenceExpression Host => PrimaryEndpoint.Property(EndpointProperty.Host); /// <summary> /// Gets the port endpoint reference for this resource. /// </summary> public EndpointReferenceExpression Port => PrimaryEndpoint.Property(EndpointProperty.Port); /// <summary> /// Gets the parameter that contains the Redis server password. /// </summary> public ParameterResource? PasswordParameter { get; private set; } /// <summary> /// Indicates whether TLS is enabled for the Redis server. /// </summary> /// <remarks> /// This property proxies through to <see cref="EndpointAnnotation.TlsEnabled"/> on the /// <see cref="PrimaryEndpoint"/>. When set to <see langword="true"/>, the connection string /// expression dynamically includes <c>,ssl=true</c> and the URI expression uses the /// <c>rediss://</c> scheme. This value is resolved lazily at expression evaluation time, /// avoiding timing issues when TLS is enabled later in the application lifecycle /// (e.g., during the <c>BeforeStartEvent</c>). /// </remarks> public bool TlsEnabled => PrimaryEndpoint.TlsEnabled; /// <summary> /// Arguments for the Dockerfile /// </summary> internal List<string> Args { get; set; } = new(); private ReferenceExpression BuildConnectionString() { var builder = new ReferenceExpressionBuilder(); builder.Append($"{PrimaryEndpoint.Property(EndpointProperty.HostAndPort)}"); if (PasswordParameter is not null) { builder.Append($",password={PasswordParameter}"); } builder.Append($"{PrimaryEndpoint.GetTlsValue( enabledValue: ReferenceExpression.Create($",ssl=true"), disabledValue: ReferenceExpression.Empty)}"); return builder.Build(); } /// <summary> /// Gets the connection string expression for the Redis server. /// </summary> public ReferenceExpression ConnectionStringExpression { get { if (this.TryGetLastAnnotation<ConnectionStringRedirectAnnotation>(out var connectionStringAnnotation)) { return connectionStringAnnotation.Resource.ConnectionStringExpression; } return BuildConnectionString(); } } /// <summary> /// Gets the connection string for the Redis server. /// </summary> /// <param name="cancellationToken"> A <see cref="CancellationToken"/> to observe while waiting for the task to complete.</param> /// <returns>A connection string for the redis server in the form "host:port".</returns> public ValueTask<string?> GetConnectionStringAsync(CancellationToken cancellationToken = default) { if (this.TryGetLastAnnotation<ConnectionStringRedirectAnnotation>(out var connectionStringAnnotation)) { return connectionStringAnnotation.Resource.GetConnectionStringAsync(cancellationToken); } return BuildConnectionString().GetValueAsync(cancellationToken); } internal void SetPassword(ParameterResource? password) { PasswordParameter = password; } /// <summary> /// Gets the connection URI expression for the Redis server. /// </summary> /// <remarks> /// Format: <c>redis://[:{password}@]{host}:{port}</c>. The password segment is omitted when no password is configured. /// </remarks> public ReferenceExpression UriExpression { get { var builder = new ReferenceExpressionBuilder(); builder.Append($"{PrimaryEndpoint.Property(EndpointProperty.Scheme)}"); builder.AppendLiteral("://"); if (PasswordParameter is not null) { builder.Append($":{PasswordParameter:uri}@"); } builder.Append($"{Host}"); builder.AppendLiteral(":"); builder.Append($"{Port}"); return builder.Build(); } } IEnumerable<KeyValuePair<string, ReferenceExpression>> IResourceWithConnectionString.GetConnectionProperties() { yield return new("Host", ReferenceExpression.Create($"{Host}")); yield return new("Port", ReferenceExpression.Create($"{Port}")); if (PasswordParameter is not null) { yield return new("Password", ReferenceExpression.Create($"{PasswordParameter}")); } yield return new("Uri", UriExpression); } }