Skip to content

Commit 53389af

Browse files
committed
Move encoding to ReferenceExpression
Fixes #12070
1 parent 36c145d commit 53389af

File tree

4 files changed

+143
-150
lines changed

4 files changed

+143
-150
lines changed

src/Aspire.Hosting.Azure.AppContainers/BaseContainerAppContext.cs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,21 +253,6 @@ BicepValue<string> GetHostValue(string? prefix = null, string? suffix = null)
253253
return (AllocateParameter(output, secretType: secretType), secretType);
254254
}
255255

256-
if (value is IUrlEncoderProvider encoder && encoder.ValueProvider is { } valueProvider)
257-
{
258-
// Evaluate the inner value to get the bicep expression
259-
var (innerValue, secret) = ProcessValue(valueProvider, secretType: secretType, parent: parent);
260-
261-
var innerExpression = innerValue switch
262-
{
263-
ProvisioningParameter p => p.Value.Compile(),
264-
IBicepValue b => b.Compile(),
265-
_ => throw new ArgumentException($"Invalid expression type for url-encoding: {innerValue.GetType()}")
266-
};
267-
268-
return (new FunctionCallExpression(new IdentifierExpression("uriComponent"), innerExpression), secret);
269-
}
270-
271256
#pragma warning disable CS0618 // Type or member is obsolete
272257
if (value is BicepSecretOutputReference)
273258
{
@@ -303,7 +288,14 @@ BicepValue<string> GetHostValue(string? prefix = null, string? suffix = null)
303288
// Special case simple expressions
304289
if (expr.Format == "{0}" && expr.ValueProviders.Count == 1)
305290
{
306-
return ProcessValue(expr.ValueProviders[0], secretType, parent: parent);
291+
var val = ProcessValue(expr.ValueProviders[0], secretType, parent: parent);
292+
293+
if (expr.StringFormats[0] is string format)
294+
{
295+
val = (FormatBicepExpression(val, format), secretType);
296+
}
297+
298+
return val;
307299
}
308300

309301
var args = new object[expr.ValueProviders.Count];
@@ -319,11 +311,31 @@ BicepValue<string> GetHostValue(string? prefix = null, string? suffix = null)
319311
finalSecretType = SecretType.Normal;
320312
}
321313

314+
if (expr.StringFormats[index] is string format)
315+
{
316+
val = FormatBicepExpression(val, format);
317+
}
318+
322319
args[index++] = val;
323320
}
324321

325322
return (FormattableStringFactory.Create(expr.Format, args), finalSecretType);
326323

324+
static BicepExpression FormatBicepExpression(object val, string format)
325+
{
326+
var innerExpression = val switch
327+
{
328+
ProvisioningParameter p => p.Value.Compile(),
329+
IBicepValue b => b.Compile(),
330+
_ => throw new ArgumentException($"Invalid expression type for url-encoding: {val.GetType()}")
331+
};
332+
333+
return format.ToLowerInvariant() switch
334+
{
335+
"uri" => new FunctionCallExpression(new IdentifierExpression("uriComponent"), innerExpression),
336+
_ => throw new NotSupportedException($"The format '{format}' is not supported.")
337+
};
338+
}
327339
}
328340

329341
if (value is IManifestExpressionProvider manifestExpressionProvider)

src/Aspire.Hosting.Azure.AppService/AzureAppServiceWebsiteContext.cs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,21 +141,6 @@ private void ProcessEndpoints()
141141
return (AllocateParameter(output, secretType: secretType), secretType);
142142
}
143143

144-
if (value is IUrlEncoderProvider encoder && encoder.ValueProvider is { } valueProvider)
145-
{
146-
// Evaluate the inner value to get the bicep expression
147-
var (innerValue, secret) = ProcessValue(valueProvider, secretType: secretType, parent: parent);
148-
149-
var innerExpression = innerValue switch
150-
{
151-
ProvisioningParameter p => p.Value.Compile(),
152-
IBicepValue b => b.Compile(),
153-
_ => throw new ArgumentException($"Invalid expression type for url-encoding: {innerValue.GetType()}")
154-
};
155-
156-
return (new FunctionCallExpression(new IdentifierExpression("uriComponent"), innerExpression), secret);
157-
}
158-
159144
if (value is IAzureKeyVaultSecretReference vaultSecretReference)
160145
{
161146
if (parent is null)
@@ -178,7 +163,14 @@ private void ProcessEndpoints()
178163
{
179164
if (expr.Format == "{0}" && expr.ValueProviders.Count == 1)
180165
{
181-
return ProcessValue(expr.ValueProviders[0], secretType, parent);
166+
var val = ProcessValue(expr.ValueProviders[0], secretType, parent: parent);
167+
168+
if (expr.StringFormats[0] is string format)
169+
{
170+
val = (FormatBicepExpression(val, format), secretType);
171+
}
172+
173+
return val;
182174
}
183175

184176
var args = new object[expr.ValueProviders.Count];
@@ -192,10 +184,32 @@ private void ProcessEndpoints()
192184
{
193185
finalSecretType = SecretType.Normal;
194186
}
187+
188+
if (expr.StringFormats[index] is string format)
189+
{
190+
val = FormatBicepExpression(val, format);
191+
}
192+
195193
args[index++] = val;
196194
}
197195

198196
return (FormattableStringFactory.Create(expr.Format, args), finalSecretType);
197+
198+
static BicepExpression FormatBicepExpression(object val, string format)
199+
{
200+
var innerExpression = val switch
201+
{
202+
ProvisioningParameter p => p.Value.Compile(),
203+
IBicepValue b => b.Compile(),
204+
_ => throw new ArgumentException($"Invalid expression type for url-encoding: {val.GetType()}")
205+
};
206+
207+
return format.ToLowerInvariant() switch
208+
{
209+
"uri" => new FunctionCallExpression(new IdentifierExpression("uriComponent"), innerExpression),
210+
_ => throw new NotSupportedException($"The format '{format}' is not supported.")
211+
};
212+
}
199213
}
200214

201215
if (value is IManifestExpressionProvider manifestExpressionProvider)

src/Aspire.Hosting/ApplicationModel/IUrlEncoderProvider.cs

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,57 @@
44
namespace Aspire.Hosting.ApplicationModel;
55

66
/// <summary>
7-
/// Represents a service that can url-encode a ReferenceExpression.
7+
/// Defines the format of a <see cref="ReferenceExpression"/>.
88
/// </summary>
9-
public interface IUrlEncoderProvider : IValueWithReferences, IValueProvider, IManifestExpressionProvider
9+
public enum ReferenceExpressionFormats
1010
{
1111
/// <summary>
12-
/// The value provider.
12+
/// No special formatting.
1313
/// </summary>
14-
object ValueProvider { get; }
14+
None = 0,
15+
16+
/// <summary>
17+
/// The value should be URL-encoded.
18+
/// </summary>
19+
UrlEncoded = 1,
1520
}
1621

17-
internal class UrlEncoderProvider<T> : IUrlEncoderProvider where T : IValueProvider, IManifestExpressionProvider
22+
internal class ManifestEncoder : IReferenceExpressionEncoder
1823
{
19-
private readonly T _valueProvider;
20-
21-
public UrlEncoderProvider(T valueProvider)
22-
{
23-
_valueProvider = valueProvider;
24-
}
25-
26-
public object ValueProvider => _valueProvider;
27-
28-
public string ValueExpression
24+
public string EncodeValue(string value, ReferenceExpressionFormats format)
2925
{
30-
get
26+
return format switch
3127
{
32-
var expression = _valueProvider.ValueExpression;
33-
34-
return expression;
35-
}
36-
}
37-
38-
/// <inheritdoc/>
39-
public async ValueTask<string?> GetValueAsync(CancellationToken cancellationToken = default)
40-
{
41-
var value = await _valueProvider.GetValueAsync(cancellationToken).ConfigureAwait(false);
42-
43-
// Don't double-encode
44-
if (value is null)
45-
{
46-
return null;
47-
}
48-
49-
return Uri.EscapeDataString(value);
28+
ReferenceExpressionFormats.None => value,
29+
ReferenceExpressionFormats.UrlEncoded => $"uriComponent({value})",
30+
_ => throw new NotSupportedException($"The format '{format}' is not supported."),
31+
};
5032
}
33+
}
5134

52-
IEnumerable<object> IValueWithReferences.References
35+
internal class ValueEncoder : IReferenceExpressionEncoder
36+
{
37+
public string EncodeValue(string value, ReferenceExpressionFormats format)
5338
{
54-
get
39+
return format switch
5540
{
56-
if (_valueProvider is IResource)
57-
{
58-
yield return _valueProvider;
59-
}
60-
61-
if (_valueProvider is IValueWithReferences valueWithReferences)
62-
{
63-
foreach (var reference in valueWithReferences.References)
64-
{
65-
yield return reference;
66-
}
67-
}
68-
}
41+
ReferenceExpressionFormats.None => value,
42+
ReferenceExpressionFormats.UrlEncoded => Uri.EscapeDataString(value),
43+
_ => throw new NotSupportedException($"The format '{format}' is not supported."),
44+
};
6945
}
7046
}
47+
48+
/// <summary>
49+
/// Provides methods to encode values and Bicep expressions based on the specified <see cref="ReferenceExpressionFormats"/>.
50+
/// </summary>
51+
public interface IReferenceExpressionEncoder
52+
{
53+
/// <summary>
54+
/// Encodes the given value according to the specified format.
55+
/// </summary>
56+
/// <param name="value"></param>
57+
/// <param name="format"></param>
58+
/// <returns></returns>
59+
string EncodeValue(string value, ReferenceExpressionFormats format);
60+
}

0 commit comments

Comments
 (0)