-
Notifications
You must be signed in to change notification settings - Fork 363
dotnet deploy optimize skill #11
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
Changes from 7 commits
8efed71
7777dcc
b4eedf0
60bdae5
cd40829
361295f
3e011dd
9001415
2b8526e
22b8d91
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,287 @@ | ||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||
| name: dotnet-deploy-optimize | ||||||||||||||||||||||||||
| description: Optimizes .NET 8+ application deployments by analyzing publish configuration, trimming, Native AOT, Docker images, CI/CD pipelines, environment configuration, and health checks. Use when preparing a .NET app for production deployment or improving an existing deployment pipeline. | ||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # .NET Deployment Optimization | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Analyze and optimize a .NET 8+ application's deployment pipeline to produce smaller, faster, and more reliable production artifacts. The skill walks through publish modes, trimming, Native AOT, container optimization, CI/CD tuning, configuration management, and health-check readiness. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## When to Use | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - Preparing a .NET 8+ application for its first production deployment | ||||||||||||||||||||||||||
| - Reducing published application size or cold-start latency | ||||||||||||||||||||||||||
| - Optimizing Docker images for a .NET service | ||||||||||||||||||||||||||
| - Improving CI/CD build times for .NET projects | ||||||||||||||||||||||||||
| - Adding health checks or readiness probes to a .NET service | ||||||||||||||||||||||||||
| - Reviewing an existing deployment pipeline for inefficiencies | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## When Not to Use | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - The project targets .NET Framework (not .NET Core/.NET 8+) | ||||||||||||||||||||||||||
| - The goal is application-level performance profiling (CPU, memory, hot-path optimization) | ||||||||||||||||||||||||||
| - The project is a library or NuGet package (no deployment artifact) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Inputs | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Input | Required | Description | | ||||||||||||||||||||||||||
| |-------|----------|-------------| | ||||||||||||||||||||||||||
| | Project or solution path | Yes | Path to the `.csproj`, `.fsproj`, or `.sln` file | | ||||||||||||||||||||||||||
| | Target environment | No | Description of where the app will run (e.g., Linux container, Windows IIS, cloud PaaS) | | ||||||||||||||||||||||||||
| | Current Dockerfile | No | Existing Dockerfile, if one exists | | ||||||||||||||||||||||||||
| | CI/CD pipeline config | No | Existing pipeline file (e.g., GitHub Actions YAML, Azure Pipelines YAML) | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Workflow | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Step 1: Assess the current project configuration | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1. Read the project file(s) and identify the target framework, output type, and any existing publish settings. | ||||||||||||||||||||||||||
| 2. Check for a `Properties/launchSettings.json`, `appsettings.json`, and `appsettings.*.json` files. | ||||||||||||||||||||||||||
| 3. Note any existing `PublishTrimmed`, `PublishAot`, `PublishSingleFile`, `ReadyToRun`, or `SelfContained` properties. | ||||||||||||||||||||||||||
| 4. Identify the application type using these signals: | ||||||||||||||||||||||||||
| - **Web API / MVC / Razor Pages**: `<Project Sdk="Microsoft.NET.Sdk.Web">` with no Blazor packages | ||||||||||||||||||||||||||
| - **Blazor**: `Sdk="Microsoft.NET.Sdk.Web"` plus `Microsoft.AspNetCore.Components` packages | ||||||||||||||||||||||||||
| - **gRPC**: `Sdk="Microsoft.NET.Sdk.Web"` plus `Grpc.AspNetCore` package reference | ||||||||||||||||||||||||||
| - **Worker Service**: `Sdk="Microsoft.NET.Sdk.Worker"`, or `Sdk="Microsoft.NET.Sdk"` with a `BackgroundService` or `IHostedService` implementation and a reference to `Microsoft.Extensions.Hosting` | ||||||||||||||||||||||||||
| - **Console**: `Sdk="Microsoft.NET.Sdk"` with `<OutputType>Exe</OutputType>` | ||||||||||||||||||||||||||
| - **WinForms / WPF**: `<UseWindowsForms>true</UseWindowsForms>` or `<UseWPF>true</UseWPF>` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Step 2: Recommend a publish mode | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Evaluate and recommend the most appropriate publish mode based on the application type: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Mode | When to use | | ||||||||||||||||||||||||||
| |------|-------------| | ||||||||||||||||||||||||||
| | Framework-dependent | Target already has the .NET runtime installed; smallest artifact | | ||||||||||||||||||||||||||
| | Self-contained | Target may not have the runtime; trade size for portability | | ||||||||||||||||||||||||||
| | Single-file | Self-contained apps that benefit from a single executable | | ||||||||||||||||||||||||||
| | ReadyToRun (R2R) | Self-contained apps where faster startup is needed but full AOT is not feasible; pre-compiles IL to native code while keeping JIT as a fallback | | ||||||||||||||||||||||||||
| | Native AOT | Console or API apps needing minimal startup time and memory; no reflection-heavy libraries | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Provide the recommended `dotnet publish` command with appropriate flags: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||
| # Example: self-contained single-file publish for Linux | ||||||||||||||||||||||||||
| dotnet publish -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Or equivalently, set the properties in the project file: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ```xml | ||||||||||||||||||||||||||
| <!-- Example: project file properties for single-file self-contained --> | ||||||||||||||||||||||||||
| <PropertyGroup> | ||||||||||||||||||||||||||
| <PublishSingleFile>true</PublishSingleFile> | ||||||||||||||||||||||||||
| <SelfContained>true</SelfContained> | ||||||||||||||||||||||||||
| <RuntimeIdentifier>linux-x64</RuntimeIdentifier> | ||||||||||||||||||||||||||
| </PropertyGroup> | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Step 2b: Check publish setting compatibility | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Before combining publish properties, verify the combination is valid. The following table lists settings that conflict or are redundant when used together: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Setting A | Setting B | Outcome | Explanation | | ||||||||||||||||||||||||||
| |-----------|-----------|---------|-------------| | ||||||||||||||||||||||||||
| | `PublishAot` | `PublishSingleFile` | **Conflict** | AOT produces a single native binary by default; `PublishSingleFile` is for IL-based apps and is ignored with AOT | | ||||||||||||||||||||||||||
| | `PublishAot` | `ReadyToRun` | **Conflict** | ReadyToRun pre-compiles IL to native via crossgen; AOT replaces the IL pipeline entirely, making R2R meaningless | | ||||||||||||||||||||||||||
| | `PublishAot` | `SelfContained=false` | **Conflict** | AOT output is always self-contained; setting `SelfContained` to false is contradictory and will cause a build error | | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| | `PublishAot` | `PublishTrimmed` | **Redundant** | AOT implies trimming; setting `PublishTrimmed` explicitly is unnecessary (but not harmful) | | ||||||||||||||||||||||||||
| | `PublishSingleFile` | `SelfContained=false` | **Not recommended** | Framework-dependent single-file bundles are supported but rarely useful; the host still requires the shared runtime | | ||||||||||||||||||||||||||
| | `ReadyToRun` | `PublishTrimmed` | **Caution** | Supported but may increase size because R2R adds native code on top of IL; trimming savings can be offset by R2R overhead | | ||||||||||||||||||||||||||
| | `ReadyToRun` | `SelfContained=false` | **Conflict** | ReadyToRun pre-compiles app IL to native code and requires the runtime to be bundled; framework-dependent apps cannot use R2R | | ||||||||||||||||||||||||||
| | `PublishTrimmed` | `SelfContained=false` | **Conflict** | Trimming requires self-contained deployment; framework-dependent apps cannot be trimmed | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| When reviewing a project file, flag any of these combinations and recommend removing the conflicting or redundant property. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Step 3: Apply trimming and tree-shaking | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| > **Skip this step** if Native AOT was chosen in Step 2 — AOT applies trimming automatically. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| 1. Check if the application is trim-compatible by scanning for known trim-incompatible patterns: | ||||||||||||||||||||||||||
| - Heavy use of `System.Reflection` and using string representations of types, strongly typed reflection is not problematic | ||||||||||||||||||||||||||
| - Dynamic assembly loading | ||||||||||||||||||||||||||
| - `System.Text.Json` source generators not configured | ||||||||||||||||||||||||||
| - COM interop | ||||||||||||||||||||||||||
| - Check trim-compatibility of dependencies, including from nuget | ||||||||||||||||||||||||||
|
Comment on lines
+84
to
+88
|
||||||||||||||||||||||||||
| - Heavy use of `System.Reflection` and using string representations of types, strongly typed reflection is not problematic | |
| - Dynamic assembly loading | |
| - `System.Text.Json` source generators not configured | |
| - COM interop | |
| - Check trim-compatibility of dependencies, including from nuget | |
| - Reflection usage: | |
| - Heavy use of `System.Reflection` APIs that rely on string-based type or member names (for example, `Type.GetType("Namespace.TypeName")`) | |
| - Strongly typed reflection (such as `typeof`, `nameof`, or expression-based access) is generally trim-safe | |
| - Dynamic assembly loading | |
| - `System.Text.Json` source generators not configured | |
| - COM interop | |
| - Check trim-compatibility of dependencies, including from NuGet |
Copilot
AI
Feb 20, 2026
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.
The Worker Service health-check snippet uses builder.WebHost.UseKestrel(...), builder.Build(), and app.MapHealthChecks(...) without showing where builder comes from. As written, it won’t compile in a typical Worker Service template (Host.CreateDefaultBuilder / HostApplicationBuilder) and may confuse users. Suggest providing a complete, self-contained example that matches the Worker template (or explicitly state this option switches to a WebApplicationBuilder-based minimal host alongside the worker).
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.
The skill refers to the publish setting as
ReadyToRun, but in .NET/MSBuild the publish property isPublishReadyToRun(see other skills in this repo). UsingReadyToRunhere will mislead readers and the later compatibility matrix/rubric. Recommend renaming toPublishReadyToRunthroughout (including the eval fixtures).