Skip to content

C#/.NET Hook Executor #7623

Description

@wbreza

Background & Motivation

.NET developers building Azure applications with azd need hook support in C#. The .NET SDK is already commonly installed alongside azd for Aspire and other .NET workloads. The existing dotnet.Cli in azd provides restore/build/run capabilities that the executor can reuse.

Parent Epic: #7435 — Multi-Language Hook Support
Phase 1 PR: #7451 — delivered the extensible framework and Python support
Independent of: #7621 (JavaScript) and #7622 (TypeScript) — can be implemented in parallel

User Story

As an azd user, I want to write hook scripts in C# (.cs files or .csproj projects) so that I can use .NET for hook automation, especially in Aspire-based projects.

Existing Infrastructure (from Phase 1)

The following already exist and are shared by all new executors:

  • HookExecutor interface (pkg/tools/script.go) — Prepare/Execute/Cleanup lifecycle
  • HookKind constant dotnet (pkg/tools/language/executor.go)
  • InferKindFromPath() — maps .cs→dotnet
  • Project discovery (pkg/tools/language/project_discovery.go) — walk-up for *.*proj
  • IoC-based executor resolution in hooks_runner.go
  • dotnet.Cli singleton in cmd/container.go
  • Schema support for kind: dotnet in azure.yaml.json
  • ExecutionContext with Cwd, EnvVars, BoundaryDir, etc.

Solution Approach

  • Create dotnetExecutor in pkg/tools/language/dotnet_executor.go implementing HookExecutor
  • Two execution modes:
    • Project mode (with .csproj): dotnet restoredotnet builddotnet run
    • Single-file mode (.cs only, .NET 10+): dotnet run script.cs (if supported by installed SDK)
  • Prepare():
    • Validate .NET SDK installed via existing dotnet.Cli — hard error with ErrorWithSuggestion if missing
    • Discover .csproj files via DiscoverProjectFile() (glob pattern *.*proj already in project_discovery.go)
    • If project found: dotnet restore
    • If single-file and .NET 10+: no restore needed
    • If single-file and .NET < 10: error with suggestion to create a project or upgrade SDK
  • Execute():
    • Project mode: dotnet run --project path/to/project.csproj
    • Single-file: dotnet run script.cs
    • Pass environment variables via ExecutionContext.EnvVars
  • Cleanup(): No-op
  • Register "dotnet" as named transient in cmd/container.go
  • Update docs/language-hooks.md with .NET section

Acceptance Criteria

  • .cs hook scripts auto-detected and executed via .NET SDK
  • .csproj projects discovered via walk-up, restored and built before execution
  • dotnet restore and dotnet build run during Prepare phase
  • Single-file .cs scripts supported on .NET 10+ without requiring a .csproj
  • Missing .NET SDK → clear error with install URL via ErrorWithSuggestion
  • Environment variables passed through to script process
  • kind: dotnet explicit override works in azure.yaml
  • Existing shell, Python, JS, and TS hooks unaffected
  • IoC registration as named transient "dotnet" in container.go

Out of Scope

  • F# or VB.NET hook support
  • .NET Framework (Windows-only) — only .NET SDK (cross-platform)
  • NuGet package management beyond what dotnet restore handles
  • Custom MSBuild targets or properties

Testing Expectations

  • Unit tests for dotnetExecutor (project and single-file modes)
  • Unit tests for .csproj discovery and SDK version detection
  • E2E test: .csproj project → restore → build → run → verify output
  • E2E test: single-file .cs on .NET 10+ → run → verify
  • E2E test: missing .NET SDK → error with suggestion
  • E2E test: continueOnError: true behavior
  • E2E test: service-level .NET hooks

Constraints

  • Must reuse existing dotnet.Cli singleton — do not create a separate .NET wrapper
  • Follow the Prepare/Execute/Cleanup lifecycle pattern
  • SDK version detection needed for single-file mode gating

Related Issues

Metadata

Metadata

Assignees

Labels

Fields

No fields configured for Feature.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions