-
Notifications
You must be signed in to change notification settings - Fork 159
feat(dapr): add IValueProvider support for component metadata configuration #810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
FullStackChef
merged 22 commits into
CommunityToolkit:main
from
gabynevada:feat/dapr-metadata-endpoint-reference
Sep 6, 2025
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
59b2020
feat(dapr): add WaitFor support for Dapr sidecar resources
gabynevada 6e67899
feat(dapr): add WithMetadata overload for EndpointReference
gabynevada 807f941
feat: add value provider implementation
gabynevada 757691a
feat: test using secrets with envs
gabynevada 1cc5328
chore: add test for dapr pubsub
gabynevada 4bd42cc
chore: use simpler endpoint prefix
gabynevada cc291a6
feat: replace overload with IValueProvider for flexibility
gabynevada a5e5a75
chore: use target port for example
gabynevada 60b2b1b
chore: remove test method
gabynevada e6c6031
feat: simplify logic by avoiding secret placeholders
gabynevada 7e3e218
chore: make configuration example cleaner
gabynevada 4fda6b0
refactor: consolidate value provider tests and remove placeholder pat…
gabynevada 744076a
chore: remove unused comments and unnecesarry tests
gabynevada fe25c66
chore: remove unused using
gabynevada e409ed1
feat: enhance Dapr sidecar lifecycle management and metadata configur…
gabynevada a31d1fe
feat(dapr): add DaprComponent wait lifecycle implementation
gabynevada 50a9567
feat(dapr): add component dependency wait support via SetupComponentL…
gabynevada f839ea0
chore: remove providers for component lyfecycle
gabynevada 93d851a
feat: pass the wait annotations from the configuration resource to th…
gabynevada 1566eda
chore: add waitfor for dapr state store to redis
gabynevada 25242ce
refactor(dapr): use component lifetimes instead of passing wait annot…
gabynevada e27b40e
fix(dapr): use WaitUntilHealthy for component dependencies
gabynevada File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| using Aspire.Hosting.ApplicationModel; | ||
|
|
||
| namespace CommunityToolkit.Aspire.Hosting.Dapr; | ||
| internal sealed record DaprComponentConfigurationAnnotation(Func<DaprComponentSchema, Task> Configure) : IResourceAnnotation; | ||
| internal sealed record DaprComponentConfigurationAnnotation(Func<DaprComponentSchema, CancellationToken, Task> Configure) : IResourceAnnotation; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| using Aspire.Hosting.ApplicationModel; | ||
|
|
||
| namespace CommunityToolkit.Aspire.Hosting.Dapr; | ||
|
|
||
| /// <summary> | ||
| /// Annotation that tracks value providers that need deferred resolution for Dapr component metadata | ||
| /// </summary> | ||
| internal sealed record DaprComponentValueProviderAnnotation(string MetadataName, string EnvironmentVariableName, IValueProvider ValueProvider) : IResourceAnnotation; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,9 +3,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Aspire.Hosting; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Aspire.Hosting.ApplicationModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Aspire.Hosting.Eventing; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Aspire.Hosting.Lifecycle; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Aspire.Hosting.Utils; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.DependencyInjection; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Hosting; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Logging; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Options; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -32,6 +34,10 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string appHostDirectory = GetAppHostDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set up WaitAnnotations for Dapr components based on their value provider dependencies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SetupComponentLifecycle(appModel); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var onDemandResourcesPaths = await StartOnDemandDaprComponentsAsync(appModel, cancellationToken).ConfigureAwait(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var sideCars = new List<ExecutableResource>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -71,35 +77,41 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var componentReferenceAnnotations = resource.Annotations.OfType<DaprComponentReferenceAnnotation>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var waitAnnotationsToCopyToDaprCli = new List<WaitAnnotation>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var secrets = new Dictionary<string, string>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var endpointEnvironmentVars = new Dictionary<string, IValueProvider>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var hasValueProviders = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach (var componentReferenceAnnotation in componentReferenceAnnotations) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if there are any value provider references that need to be added as environment variables | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (componentReferenceAnnotation.Component.TryGetAnnotationsOfType<DaprComponentValueProviderAnnotation>(out var endpointAnnotations)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach (var endpointAnnotation in endpointAnnotations) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endpointEnvironmentVars[endpointAnnotation.EnvironmentVariableName] = endpointAnnotation.ValueProvider; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hasValueProviders = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if there are any secrets that need to be added to the secret store | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (componentReferenceAnnotation.Component.TryGetAnnotationsOfType<DaprComponentSecretAnnotation>(out var secretAnnotations)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach (var secretAnnotation in secretAnnotations) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| secrets[secretAnnotation.Key] = (await secretAnnotation.Value.GetValueAsync(cancellationToken))!; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // We need to append the secret store path to the resources path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDemandResourcesPaths.TryGetValue("secretstore", out var secretStorePath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If we have any secrets or value providers, ensure the secret store path is added | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ((secrets.Count > 0 || hasValueProviders) && onDemandResourcesPaths.TryGetValue("secretstore", out var secretStorePath)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string onDemandResourcesPathDirectory = Path.GetDirectoryName(secretStorePath)!; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (onDemandResourcesPathDirectory is not null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| aggregateResourcesPaths.Add(onDemandResourcesPathDirectory); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Whilst we are passing over each component annotations collect the list of annotations to copy to the Dapr CLI. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (componentReferenceAnnotation.Component.TryGetAnnotationsOfType<WaitAnnotation>(out var componentWaitAnnotations)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| waitAnnotationsToCopyToDaprCli.AddRange(componentWaitAnnotations); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (componentReferenceAnnotation.Component.Options?.LocalPath is not null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var localPathDirectory = Path.GetDirectoryName(NormalizePath(componentReferenceAnnotation.Component.Options.LocalPath)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -120,19 +132,23 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (secrets.Count > 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (secrets.Count > 0 || endpointEnvironmentVars.Count > 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| daprSidecar.Annotations.Add(new EnvironmentCallbackAnnotation(context => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| daprSidecar.Annotations.Add(new EnvironmentCallbackAnnotation(async context => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach (var secret in secrets) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.EnvironmentVariables.TryAdd(secret.Key, secret.Value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add value provider references | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreach (var (envVarName, valueProvider) in endpointEnvironmentVars) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var value = await valueProvider.GetValueAsync(context.CancellationToken); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.EnvironmentVariables.TryAdd(envVarName, value ?? string.Empty); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+137
to
+149
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| daprSidecar.Annotations.Add(new EnvironmentCallbackAnnotation(async context => | |
| { | |
| foreach (var secret in secrets) | |
| { | |
| context.EnvironmentVariables.TryAdd(secret.Key, secret.Value); | |
| } | |
| // Add value provider references | |
| foreach (var (envVarName, valueProvider) in endpointEnvironmentVars) | |
| { | |
| var value = await valueProvider.GetValueAsync(context.CancellationToken); | |
| context.EnvironmentVariables.TryAdd(envVarName, value ?? string.Empty); | |
| } | |
| // Precompute all value provider results asynchronously | |
| var precomputedEnvVars = new Dictionary<string, string>(); | |
| foreach (var secret in secrets) | |
| { | |
| precomputedEnvVars[secret.Key] = secret.Value; | |
| } | |
| foreach (var (envVarName, valueProvider) in endpointEnvironmentVars) | |
| { | |
| // Synchronously block here to get the value | |
| // (since we're already in an async method, this is safe) | |
| var value = valueProvider.GetValueAsync(cancellationToken).GetAwaiter().GetResult(); | |
| precomputedEnvVars[envVarName] = value ?? string.Empty; | |
| } | |
| daprSidecar.Annotations.Add(new EnvironmentCallbackAnnotation(context => | |
| { | |
| foreach (var kvp in precomputedEnvVars) | |
| { | |
| context.EnvironmentVariables.TryAdd(kvp.Key, kvp.Value); | |
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This internal class lacks XML documentation comments. As it's a key component for value provider functionality, it should have proper documentation explaining its purpose and usage.