From ce340b42cf94d71c6c4244205d00f5a909123a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=E1=BA=A7n=20Ho=C3=A0ng=20T=C3=BA?= Date: Sat, 28 Mar 2026 23:14:27 +0700 Subject: [PATCH 1/3] feat: add Logger property to ExecuteCommandContext --- .../ApplicationModel/ResourceCommandAnnotation.cs | 6 ++++++ .../ApplicationModel/ResourceCommandService.cs | 3 ++- src/Aspire.Hosting/api/Aspire.Hosting.cs | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs b/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs index 3b47ee839bc..46513404b28 100644 --- a/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs +++ b/src/Aspire.Hosting/ApplicationModel/ResourceCommandAnnotation.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using Microsoft.Extensions.Logging; namespace Aspire.Hosting.ApplicationModel; @@ -242,4 +243,9 @@ public sealed class ExecuteCommandContext /// The cancellation token. /// public required CancellationToken CancellationToken { get; init; } + + /// + /// The logger for the resource. + /// + public required ILogger Logger { get; init; } } diff --git a/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs b/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs index d3b07a0db98..95a4043e980 100644 --- a/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs +++ b/src/Aspire.Hosting/ApplicationModel/ResourceCommandService.cs @@ -161,7 +161,8 @@ internal async Task ExecuteCommandCoreAsync(string resourc { ResourceName = resourceId, ServiceProvider = _serviceProvider, - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + Logger = logger }; var result = await annotation.ExecuteCommand(context).ConfigureAwait(false); diff --git a/src/Aspire.Hosting/api/Aspire.Hosting.cs b/src/Aspire.Hosting/api/Aspire.Hosting.cs index e5b71318cee..3792817eba2 100644 --- a/src/Aspire.Hosting/api/Aspire.Hosting.cs +++ b/src/Aspire.Hosting/api/Aspire.Hosting.cs @@ -2042,6 +2042,8 @@ public sealed partial class ExecuteCommandContext { public required System.Threading.CancellationToken CancellationToken { get { throw null; } init { } } + public required Microsoft.Extensions.Logging.ILogger Logger { get { throw null; } init { } } + public required string ResourceName { get { throw null; } init { } } public required System.IServiceProvider ServiceProvider { get { throw null; } init { } } From bbecc634b576dbc7ec59c9a6726ed5c6b61ed190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=E1=BA=A7n=20Ho=C3=A0ng=20T=C3=BA?= Date: Tue, 31 Mar 2026 00:29:34 +0700 Subject: [PATCH 2/3] fix: regenerate snapshots for ExecuteCommandContext.Logger property Added Logger getter/setter methods to all 5 language SDK snapshots (Go, Java, Python, Rust, TypeScript) following the existing pattern from EnvironmentCallbackContext.Logger. --- .../api/Aspire.Hosting.Capabilities.txt | 3 +++ ...TwoPassScanningGeneratedAspire.verified.go | 25 +++++++++++++++++++ ...oPassScanningGeneratedAspire.verified.java | 19 ++++++++++++++ ...TwoPassScanningGeneratedAspire.verified.py | 17 +++++++++++++ ...TwoPassScanningGeneratedAspire.verified.rs | 19 ++++++++++++++ ...TwoPassScanningGeneratedAspire.verified.ts | 11 ++++++++ 6 files changed, 94 insertions(+) diff --git a/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt b/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt index b29e6b7e0d9..f1bd2d74200 100644 --- a/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt +++ b/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt @@ -52,6 +52,7 @@ Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineStepContext [ExposeProperties] Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions [ExposeProperties] Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration [interface] Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment [interface] +Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger [interface] System.ComponentModel/System.IServiceProvider [interface] System.Private.CoreLib/System.Threading.CancellationToken @@ -133,8 +134,10 @@ Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken(con Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext) -> Aspire.Hosting/Dict Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext) -> Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> cancellationToken +Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> string Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext +Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: string) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext Aspire.Hosting.ApplicationModel/getValueAsync(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference, cancellationToken?: cancellationToken) -> string Aspire.Hosting.ApplicationModel/ReferenceExpressionBuilder.isEmpty(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpressionBuilder) -> boolean diff --git a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go index dc09cf3410b..b34f992ab29 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go +++ b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go @@ -8187,6 +8187,31 @@ func (s *ExecuteCommandContext) SetCancellationToken(value *CancellationToken) ( return result.(*ExecuteCommandContext), nil } +// Logger gets the Logger property +func (s *ExecuteCommandContext) Logger() (*ILogger, error) { + reqArgs := map[string]any{ + "context": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger", reqArgs) + if err != nil { + return nil, err + } + return result.(*ILogger), nil +} + +// SetLogger sets the Logger property +func (s *ExecuteCommandContext) SetLogger(value *ILogger) (*ExecuteCommandContext, error) { + reqArgs := map[string]any{ + "context": SerializeValue(s.Handle()), + } + reqArgs["value"] = SerializeValue(value) + result, err := s.Client().InvokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger", reqArgs) + if err != nil { + return nil, err + } + return result.(*ExecuteCommandContext), nil +} + // ExternalServiceResource wraps a handle for Aspire.Hosting/Aspire.Hosting.ExternalServiceResource. type ExternalServiceResource struct { ResourceBuilderBase diff --git a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java index e1bb1aa0e9c..233f377bb0f 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java +++ b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java @@ -9131,6 +9131,25 @@ public ExecuteCommandContext setCancellationToken(CancellationToken value) { return (ExecuteCommandContext) getClient().invokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken", reqArgs); } + /** Gets the Logger property */ + public ILogger logger() { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + return (ILogger) getClient().invokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger", reqArgs); + } + + /** Sets the Logger property */ + public ExecuteCommandContext setLogger(ILogger value) { + Map reqArgs = new HashMap<>(); + reqArgs.put("context", AspireClient.serializeValue(getHandle())); + reqArgs.put("value", AspireClient.serializeValue(value)); + return (ExecuteCommandContext) getClient().invokeCapability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger", reqArgs); + } + + public ExecuteCommandContext setLogger(HandleWrapperBase value) { + return setLogger(new ILogger(value.getHandle(), value.getClient())); + } + } // ===== ExecuteCommandResult.java ===== diff --git a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py index 8c2d50371dd..664a1132401 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py +++ b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py @@ -3343,6 +3343,23 @@ def cancel(self) -> None: ) token.cancel() + @_uncached_property + def logger(self) -> AbstractLogger: + """Gets the Logger property""" + result = self._client.invoke_capability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger', + {'context': self._handle} + ) + return typing.cast(AbstractLogger, result) + + @logger.setter + def logger(self, value: AbstractLogger) -> None: + """Sets the Logger property""" + self._client.invoke_capability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger', + {'context': self._handle, 'value': value} + ) + class InitializeResourceEvent: """Type class for InitializeResourceEvent.""" diff --git a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs index 164d20528a9..b5ea48a7857 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs +++ b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs @@ -7116,6 +7116,25 @@ impl ExecuteCommandContext { let handle: Handle = serde_json::from_value(result)?; Ok(ExecuteCommandContext::new(handle, self.client.clone())) } + + /// Gets the Logger property + pub fn logger(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ILogger::new(handle, self.client.clone())) + } + + /// Sets the Logger property + pub fn set_logger(&self, value: &ILogger) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("context".to_string(), self.handle.to_json()); + args.insert("value".to_string(), value.handle().to_json()); + let result = self.client.invoke_capability("Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ExecuteCommandContext::new(handle, self.client.clone())) + } } /// Wrapper for Aspire.Hosting/Aspire.Hosting.ExternalServiceResource diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts index c155ffe8f83..a531d10b22e 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts @@ -1501,6 +1501,17 @@ export class ExecuteCommandContext { } }; + /** Gets the Logger property */ + logger = { + get: async (): Promise => { + const handle = await this._client.invokeCapability( + 'Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger', + { context: this._handle } + ); + return new Logger(handle, this._client); + }, + }; + } // ============================================================================ From f6dd4234ca6f0c1ac72bf0006c1c6fe9db393cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=E1=BA=A7n=20Ho=C3=A0ng=20T=C3=BA?= Date: Tue, 31 Mar 2026 00:42:05 +0700 Subject: [PATCH 3/3] revert: undo manual API surface file edit (auto-generated per @davidfowl) --- src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt b/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt index f1bd2d74200..b29e6b7e0d9 100644 --- a/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt +++ b/src/Aspire.Hosting/api/Aspire.Hosting.Capabilities.txt @@ -52,7 +52,6 @@ Aspire.Hosting/Aspire.Hosting.Pipelines.PipelineStepContext [ExposeProperties] Aspire.Hosting/Aspire.Hosting.ProjectResourceOptions [ExposeProperties] Microsoft.Extensions.Configuration.Abstractions/Microsoft.Extensions.Configuration.IConfiguration [interface] Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.IHostEnvironment [interface] -Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger [interface] System.ComponentModel/System.IServiceProvider [interface] System.Private.CoreLib/System.Threading.CancellationToken @@ -134,10 +133,8 @@ Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.cancellationToken(con Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.environmentVariables(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext) -> Aspire.Hosting/Dict Aspire.Hosting.ApplicationModel/EnvironmentCallbackContext.executionContext(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EnvironmentCallbackContext) -> Aspire.Hosting/Aspire.Hosting.DistributedApplicationExecutionContext Aspire.Hosting.ApplicationModel/ExecuteCommandContext.cancellationToken(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> cancellationToken -Aspire.Hosting.ApplicationModel/ExecuteCommandContext.logger(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger Aspire.Hosting.ApplicationModel/ExecuteCommandContext.resourceName(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext) -> string Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setCancellationToken(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: cancellationToken) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext -Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setLogger(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.ILogger) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext Aspire.Hosting.ApplicationModel/ExecuteCommandContext.setResourceName(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext, value: string) -> Aspire.Hosting/Aspire.Hosting.ApplicationModel.ExecuteCommandContext Aspire.Hosting.ApplicationModel/getValueAsync(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.EndpointReference, cancellationToken?: cancellationToken) -> string Aspire.Hosting.ApplicationModel/ReferenceExpressionBuilder.isEmpty(context: Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpressionBuilder) -> boolean