### Development Setup Documentation Example Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Document the necessary steps for setting up development tools in a README, including restoring tools, building, and testing. ```markdown ## Development Setup 1. Restore tools: `dotnet tool restore` 2. Build: `dotnet build` 3. Test: `dotnet test` ``` -------------------------------- ### Install and Configure DocFX for Documentation Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs the DocFX tool locally for generating API documentation. Usage examples show how to build and serve the documentation. ```bash # DocFX - API documentation generator dotnet tool install docfx ``` ```json "docfx": { "version": "2.78.3", "commands": ["docfx"], "rollForward": false } ``` ```bash Usage: dotnet docfx docfx.json dotnet docfx serve _site ``` -------------------------------- ### Basic Aspire Test Fixture Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-integration-testing/SKILL.md Sets up a test fixture for Aspire applications using `IAsyncLifetime`. It initializes the distributed application, starts it, and waits for a specific resource to become healthy. Ensure `Projects.YourApp_AppHost` is correctly referenced. ```csharp using Aspire.Hosting; using Aspire.Hosting.Testing; public sealed class AspireAppFixture : IAsyncLifetime { private DistributedApplication? _app; public DistributedApplication App => _app ?? throw new InvalidOperationException("App not initialized"); public async Task InitializeAsync() { var builder = await DistributedApplicationTestingBuilder .CreateAsync([ "YourApp:UseVolumes=false", "YourApp:Environment=IntegrationTest", "YourApp:Replicas=1" ]); _app = await builder.BuildAsync(); using var startupCts = new CancellationTokenSource(TimeSpan.FromMinutes(10)); await _app.StartAsync(startupCts.Token); using var healthCts = new CancellationTokenSource(TimeSpan.FromMinutes(5)); await _app.ResourceNotifications.WaitForResourceHealthyAsync("api", healthCts.Token); } public Uri GetEndpoint(string resourceName, string scheme = "https") { return _app?.GetEndpoint(resourceName, scheme) ?? throw new InvalidOperationException($"Endpoint for '{resourceName}' not found"); } public async Task DisposeAsync() { if (_app is not null) { await _app.DisposeAsync(); } } } ``` -------------------------------- ### Install and Configure EF Core CLI for Migrations Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs the EF Core CLI tools locally for managing database migrations. Usage examples demonstrate adding migrations and updating the database. ```bash # EF Core CLI for migrations dotnet tool install dotnet-ef ``` ```json "dotnet-ef": { "version": "9.0.0", "commands": ["dotnet-ef"], "rollForward": false } ``` ```bash Usage: dotnet ef migrations add InitialCreate dotnet ef database update ``` -------------------------------- ### Complete .NET Project Structure Example Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/project-structure/SKILL.md A comprehensive example of a .NET project file (.csproj) demonstrating various configuration options. ```xml Your Team Your Company Copyright © 2020-$([System.DateTime]::Now.Year) Your Company Your Product https://github.com/yourorg/yourrepo https://github.com/yourorg/yourrepo Apache-2.0 your;tags;here latest enable enable true $(NoWarn);CS1591 1.0.0 See RELEASE_NOTES.md netstandard2.0 net8.0 net9.0 true true true snupkg logo.png README.md ``` -------------------------------- ### Install Plugin Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/marketplace-publishing/SKILL.md Installs the entire dotnet-skills plugin, including all registered skills and agents. This command fetches all available content from the marketplace. ```bash /plugin install dotnet-skills ``` -------------------------------- ### Add Marketplace Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/marketplace-publishing/SKILL.md Installs the dotnet-skills marketplace for the first time. This command only needs to be run once per user. ```bash /plugin marketplace add Aaronontheweb/dotnet-skills ``` -------------------------------- ### Integrate Akka.NET Actors with Aspire for Testing Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/akka-aspire-configuration/SKILL.md Use Aspire's DistributedApplicationTestingBuilder for infrastructure setup and Akka.Hosting.TestKit for actor testing. This example shows how to initialize the Aspire application host, build and start the application, and dispose of it. ```csharp public class AkkaAspireIntegrationTests : IAsyncLifetime { private DistributedApplication? _app; public async Task InitializeAsync() { var appHost = await DistributedApplicationTestingBuilder .CreateAsync(); _app = await appHost.BuildAsync(); await _app.StartAsync(); } [Fact] public async Task ActorSystem_WithRealDatabase_ShouldPersistEvents() { // Get SQL connection string from Aspire var dbResource = _app!.GetResource("yourdb"); var connectionString = await dbResource.GetConnectionStringAsync(); // Create HttpClient to test actor endpoints var httpClient = _app.CreateHttpClient("yourapp"); // Test actor behavior through HTTP API var response = await httpClient.PostAsJsonAsync("/orders", new { OrderId = "ORDER-001", Amount = 100.00m }); response.Should().BeSuccessStatusCode(); // Verify data was persisted to real database await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); var events = await connection.QueryAsync( "SELECT EventType FROM EventJournal WHERE PersistenceId = 'order-ORDER-001'"); events.Should().Contain("OrderCreated"); } public async Task DisposeAsync() { if (_app is not null) await _app.DisposeAsync(); } } ``` -------------------------------- ### SQL Server Integration Test Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/testcontainers/database-patterns.md Configures and starts a SQL Server container for integration tests. Ensure the SA_PASSWORD is secure in production environments. ```csharp using Testcontainers; using Xunit; public class SqlServerTests : IAsyncLifetime { private readonly TestcontainersContainer _dbContainer; private IDbConnection _db; public SqlServerTests() { _dbContainer = new TestcontainersBuilder() .WithImage("mcr.microsoft.com/mssql/server:2022-latest") .WithEnvironment("ACCEPT_EULA", "Y") .WithEnvironment("SA_PASSWORD", "Your_password123") .WithPortBinding(1433, true) .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433)) .Build(); } public async Task InitializeAsync() { await _dbContainer.StartAsync(); var port = _dbContainer.GetMappedPublicPort(1433); var connectionString = $"Server=localhost,{port};Database=master;User Id=sa;Password=Your_password123;TrustServerCertificate=true"; _db = new SqlConnection(connectionString); await _db.OpenAsync(); // Create test database await _db.ExecuteAsync("CREATE DATABASE TestDb"); await _db.ExecuteAsync("USE TestDb"); // Run schema migrations await _db.ExecuteAsync(@" CREATE TABLE Orders ( Id INT PRIMARY KEY, CustomerId NVARCHAR(50) NOT NULL, Total DECIMAL(18,2) NOT NULL, CreatedAt DATETIME2 DEFAULT GETUTCDATE() )"); } public async Task DisposeAsync() { await _db.DisposeAsync(); await _dbContainer.DisposeAsync(); } [Fact] public async Task CanInsertAndRetrieveOrder() { // Arrange await _db.ExecuteAsync(@" INSERT INTO Orders (Id, CustomerId, Total) VALUES (1, 'CUST001', 99.99)"); // Act var order = await _db.QuerySingleAsync( "SELECT * FROM Orders WHERE Id = @Id", new { Id = 1 }); // Assert Assert.Equal(1, order.Id); Assert.Equal("CUST001", order.CustomerId); Assert.Equal(99.99m, order.Total); } } ``` -------------------------------- ### Install and Configure CSharpier for Code Formatting Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs CSharpier, an opinionated C# code formatter, locally. Usage examples show formatting code and checking for unformatted code in CI. ```bash # CSharpier - opinionated C# formatter dotnet tool install csharpier ``` ```json "csharpier": { "version": "0.30.3", "commands": ["dotnet-csharpier"], "rollForward": false } ``` ```bash Usage: dotnet csharpier . dotnet csharpier --check . # CI mode - fails if changes needed ``` -------------------------------- ### TestContainers Setup for SQL Server Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/testcontainers/SKILL.md Configure and start a SQL Server container for integration testing. Ensure to implement IAsyncLifetime for proper container startup and cleanup. ```csharp public class OrderRepositoryTests : IAsyncLifetime { private readonly TestcontainersContainer _dbContainer; private IDbConnection _connection; public OrderRepositoryTests() { _dbContainer = new TestcontainersBuilder() .WithImage("mcr.microsoft.com/mssql/server:2022-latest") .WithEnvironment("ACCEPT_EULA", "Y") .WithEnvironment("SA_PASSWORD", "Your_password123") .WithPortBinding(1433, true) .Build(); } public async Task InitializeAsync() { await _dbContainer.StartAsync(); var port = _dbContainer.GetMappedPublicPort(1433); var connectionString = $"Server=localhost,{port};Database=TestDb;User Id=sa;Password=Your_password123;TrustServerCertificate=true"; _connection = new SqlConnection(connectionString); await _connection.OpenAsync(); await RunMigrationsAsync(_connection); } public async Task DisposeAsync() { await _connection.DisposeAsync(); await _dbContainer.DisposeAsync(); } [Fact] public async Task GetOrder_WithRealDatabase_ReturnsOrder() { await _connection.ExecuteAsync( "INSERT INTO Orders (Id, CustomerId, Total) VALUES (1, 'CUST1', 100.00)"); var repo = new OrderRepository(_connection); var order = await repo.GetOrderAsync(1); Assert.NotNull(order); Assert.Equal("CUST1", order.CustomerId); Assert.Equal(100.00m, order.Total); } } ``` -------------------------------- ### Testcontainers for .NET SQL Server Setup Source: https://context7.com/aaronontheweb/dotnet-skills/llms.txt Configures and starts a SQL Server container for integration testing. Includes environment variables for EULA acceptance and SA password, port binding, and a wait strategy for port availability. ```csharp // NuGet packages // // public class OrderRepositoryTests : IAsyncLifetime { private readonly TestcontainersContainer _dbContainer; private IDbConnection _connection = null!; public OrderRepositoryTests() { _dbContainer = new TestcontainersBuilder() .WithImage("mcr.microsoft.com/mssql/server:2022-latest") .WithEnvironment("ACCEPT_EULA", "Y") .WithEnvironment("SA_PASSWORD", "Your_password123") .WithPortBinding(1433, true) // true = random public port .WithWaitStrategy(Wait.ForUnixContainer() .UntilPortIsAvailable(1433) .WithTimeout(TimeSpan.FromMinutes(2))) .Build(); } public async Task InitializeAsync() { await _dbContainer.StartAsync(); var port = _dbContainer.GetMappedPublicPort(1433); var cs = $"Server=localhost,{port};Database=TestDb;User Id=sa;Password=Your_password123;TrustServerCertificate=true"; _connection = new SqlConnection(cs); await _connection.OpenAsync(); await RunMigrationsAsync(_connection); } public async Task DisposeAsync() { await _connection.DisposeAsync(); await _dbContainer.DisposeAsync(); } [Fact] public async Task GetOrder_WithRealDatabase_ReturnsOrder() { await _connection.ExecuteAsync( "INSERT INTO Orders (Id, CustomerId, Total) VALUES (1, 'CUST1', 100.00)"); var repo = new OrderRepository(_connection); var order = await repo.GetOrderAsync(1); Assert.NotNull(order); Assert.Equal("CUST1", order.CustomerId); Assert.Equal(100.00m, order.Total); } } // GitHub Actions CI integration // runs-on: ubuntu-latest (Docker is pre-installed) // dotnet test tests/YourApp.IntegrationTests --filter Category=Integration ``` -------------------------------- ### Install .NET Skills Plugin Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/CLAUDE.md Users can install the dotnet-skills plugin from the marketplace using the provided bash commands. ```bash /plugin marketplace add Aaronontheweb/dotnet-skills /plugin install dotnet-skills ``` -------------------------------- ### Playwright Helper Script Usage Examples Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/playwright-ci-caching/SKILL.md Demonstrates common usage patterns for the `playwright.ps1` helper script, including installing browsers and listing installed versions. ```bash # Install browsers ./build/playwright.ps1 install --with-deps # Install specific browser ./build/playwright.ps1 install chromium # Show installed browsers ./build/playwright.ps1 install --dry-run ``` -------------------------------- ### Install .NET Skills for OpenCode Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/README.md Clone the dotnet-skills repository and copy skills and agents to the appropriate OpenCode configuration directories for global installation. ```bash git clone https://github.com/Aaronontheweb/dotnet-skills.git /tmp/dotnet-skills # Global installation (directory names must match frontmatter 'name' field) mkdir -p ~/.config/opencode/skills ~/.config/opencode/agents for skill_file in /tmp/dotnet-skills/skills/*/SKILL.md; do skill_name=$(grep -m1 "^name:" "$skill_file" | sed 's/name: *//') mkdir -p ~/.config/opencode/skills/$skill_name cp "$skill_file" ~/.config/opencode/skills/$skill_name/SKILL.md done cp /tmp/dotnet-skills/agents/*.md ~/.config/opencode/agents/ ``` -------------------------------- ### Install .NET Skills Plugin for OpenCode Source: https://context7.com/aaronontheweb/dotnet-skills/llms.txt Clone the repository and copy skills and agents to the OpenCode configuration directories for integration. ```bash git clone https://github.com/Aaronontheweb/dotnet-skills.git /tmp/dotnet-skills mkdir -p ~/.config/opencode/skills ~/.config/opencode/agents for skill_file in /tmp/dotnet-skills/skills/*/SKILL.md; do skill_name=$(grep -m1 "^name:" "$skill_file" | sed 's/name: *//') mkdir -p ~/.config/opencode/skills/$skill_name cp "$skill_file" ~/.config/opencode/skills/$skill_name/SKILL.md done cp /tmp/dotnet-skills/agents/*.md ~/.config/opencode/agents/ ``` -------------------------------- ### List Installed .NET SDKs Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/ilspy-decompile/SKILL.md This command lists all installed .NET SDKs. Knowing your SDK versions is important for compatibility and build-related tasks. ```bash dotnet --list-sdks ``` -------------------------------- ### Install Slopwatch as a Global Tool Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/slopwatch/SKILL.md Install Slopwatch globally on your machine for easy access from any project. This is an alternative to local tool installation. ```bash dotnet tool install --global Slopwatch.Cmd ``` -------------------------------- ### CI/CD Restore and Usage Example Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md In CI/CD, always run `dotnet tool restore` before using any local tool to ensure they are available. ```yaml - run: dotnet tool restore - run: dotnet docfx docs/docfx.json ``` -------------------------------- ### Aspire Test Fixture Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-mailpit-integration/SKILL.md Implements IAsyncLifetime to manage the lifecycle of a distributed application for testing. It starts the application and retrieves the Mailpit URL. ```csharp public class AspireFixture : IAsyncLifetime { private DistributedApplication? _app; private string _mailpitUrl = ""; public async Task InitializeAsync() { var appHost = await DistributedApplicationTestingBuilder .CreateAsync(); // Disable persistence for clean tests appHost.Configuration["MyApp:UseVolumes"] = "false"; _app = await appHost.BuildAsync(); await _app.StartAsync(); // Get Mailpit URL from Aspire var mailpit = _app.GetContainerResource("mailpit"); _mailpitUrl = await mailpit.GetEndpointAsync("ui"); } public HttpClient CreateClient() { var api = _app!.GetProjectResource("api"); return api.CreateHttpClient(); } public string GetMailpitUrl() => _mailpitUrl; public async Task DisposeAsync() { if (_app != null) await _app.DisposeAsync(); } } ``` -------------------------------- ### List Installed .NET Runtimes Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/ilspy-decompile/SKILL.md Use this command to list all installed .NET runtimes on your system. This helps in identifying the correct runtime environment for your assemblies. ```bash dotnet --list-runtimes ``` -------------------------------- ### Install Verify for XUnit Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/verify-email-snapshots/SKILL.md Add the Verify.Xunit package to your project to enable snapshot testing with XUnit. ```bash dotnet add package Verify.Xunit # or Verify.NUnit, Verify.MSTest ``` -------------------------------- ### Setup Meter and Metrics Class Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/opentelementry-dotnet-instrumentation/SKILL.md Group metrics by feature/component using a Meter. Use singular names, appropriate units, and a nested hierarchy for metric names. ```csharp // ✅ CORRECT: Group metrics by feature/component public sealed class OrderProcessingMetrics : IDisposable { private readonly Meter meter; private readonly Histogram processingDuration; private readonly Counter itemsProcessed; public OrderProcessingMetrics() { meter = new Meter("MyApp.OrderProcessing", "1.0.0"); // Singular names, appropriate units, nested hierarchy processingDuration = meter.CreateHistogram( "myapp.order.processing.duration", unit: "s", description: "Duration of order processing" ); itemsProcessed = meter.CreateCounter( "myapp.order.processing.count", unit: "{order}", description: "Number of orders processed" ); } public void Dispose() => meter.Dispose(); } ``` -------------------------------- ### Install JB dotnet-inspect Tool Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs the JB dotnet-inspect tool, which requires a license, for code analysis. The configuration shows the version and commands. ```bash # JB dotnet-inspect (requires license) dotnet tool install jb ``` ```json "jb": { "version": "2024.3.4", "commands": ["jb"], "rollForward": false } ``` -------------------------------- ### List Installed Local .NET Tools Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md This command lists all locally installed .NET tools. ```bash # List local tools dotnet tool list ``` -------------------------------- ### Install .NET Skills Plugin for GitHub Copilot Source: https://context7.com/aaronontheweb/dotnet-skills/llms.txt Clone the repository and copy the skills to the GitHub Copilot configuration directory for project-level integration. ```bash git clone https://github.com/Aaronontheweb/dotnet-skills.git /tmp/dotnet-skills cp -r /tmp/dotnet-skills/skills/* .github/skills/ ``` -------------------------------- ### Install Aspire CLI Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-integration-testing/ci-and-tooling.md Commands to install or update the Aspire CLI globally using the .NET CLI. ```bash # Install the Aspire CLI globally dotnet tool install -g aspire.cli # Or update existing installation dotnet tool update -g aspire.cli ``` -------------------------------- ### Repository Structure Example Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/README.md Illustrates the directory structure of the dotnet-skills repository, including plugin manifests, specialized agents, and skills. ```tree dotnet-skills/ ├── .claude-plugin/ │ └── plugin.json # Plugin manifest ├── agents/ # 5 specialized agents │ ├── akka-net-specialist.md │ ├── docfx-specialist.md │ ├── dotnet-benchmark-designer.md │ ├── dotnet-concurrency-specialist.md │ └── dotnet-performance-analyst.md └── skills/ # Flat structure (30 skills) ├── akka-best-practices/SKILL.md ├── akka-hosting-actor-patterns/SKILL.md ├── akka-net-aspire-configuration/SKILL.md ├── aspire-configuration/SKILL.md ├── aspire-integration-testing/SKILL.md ├── csharp-concurrency-patterns/SKILL.md ├── testcontainers-integration-tests/SKILL.md └── ... # (prefixed by category) ``` -------------------------------- ### Worker Service Usage with Defaults Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-service-defaults/SKILL.md Example of setting up a worker service using Aspire defaults. This demonstrates that defaults can be applied to non-web hosts as well. ```csharp var builder = Host.CreateApplicationBuilder(args); // Works for non-web hosts too builder.AddServiceDefaults(); builder.Services.AddHostedService(); var host = builder.Build(); host.Run(); ``` -------------------------------- ### API Service Usage with Defaults Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-service-defaults/SKILL.md Example of setting up an API service using Aspire defaults. It adds service defaults, controllers, and maps default endpoints. ```csharp var builder = WebApplication.CreateBuilder(args); // Add all service defaults builder.AddServiceDefaults(); // Add your services builder.Services.AddControllers(); var app = builder.Build(); // Map health endpoints app.MapDefaultEndpoints(); app.MapControllers(); app.Run(); ``` -------------------------------- ### Install and Update Packages with dotnet-outdated Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/package-management/SKILL.md Install the 'dotnet-outdated-tool' globally and use it to identify and upgrade outdated packages. This is the recommended approach for keeping dependencies current. ```bash dotnet tool install --global dotnet-outdated-tool dotnet outdated --upgrade ``` -------------------------------- ### Export and Install .NET Dev Cert (Fedora/RHEL) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/dotnet-devcert-trust/SKILL.md Commands to export the .NET development certificate and install it into the Fedora/RHEL system trust store, followed by rebuilding the trust bundle. ```bash # Export cert dotnet dev-certs https --export-path /tmp/dotnet-dev-cert.pem --format PEM --no-password # Install to Fedora trust store (different directory!) sudo cp /tmp/dotnet-dev-cert.pem /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem sudo chmod 644 /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem rm /tmp/dotnet-dev-cert.pem # Rebuild trust bundle sudo update-ca-trust # Verify openssl verify /etc/pki/ca-trust/source/anchors/dotnet-dev-cert.pem ``` -------------------------------- ### Email Test Fixture Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/verify-email-snapshots/SKILL.md Sets up the necessary services and configuration for email-related tests, implementing IAsyncLifetime for initialization and disposal. ```csharp public class EmailTestFixture : IAsyncLifetime { public IServiceProvider Services { get; private set; } = null!; public async Task InitializeAsync() { var services = new ServiceCollection(); services.AddSingleton(new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["SiteUrl"] = "https://example.com" }) .Build()); services.AddSingleton(); Services = services.BuildServiceProvider(); await Task.CompletedTask; } public Task DisposeAsync() => Task.CompletedTask; } ``` -------------------------------- ### appsettings.json for Config Discovery Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/akka-management/discovery-providers.md Example JSON configuration for `appsettings.json` to enable and configure Config Discovery for Akka.Management. ```json { "AkkaSettings": { "ClusterBootstrapOptions": { "Enabled": true, "DiscoveryMethod": "Config", "ServiceName": "my-service", "ConfigServiceEndpoints": [ "node1.local:8558", "node2.local:8558", "node3.local:8558" ] } } } ``` -------------------------------- ### Appsettings.json for Azure Discovery Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/akka-management/discovery-providers.md Example appsettings.json configuration for enabling and configuring Azure Table Storage discovery in Akka.NET. ```json { "ConnectionStrings": { "AkkaManagementAzure": "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=..." }, "AkkaSettings": { "ClusterBootstrapOptions": { "Enabled": true, "DiscoveryMethod": "AzureTableStorage", "ServiceName": "my-service", "AzureDiscoveryOptions": { "TableName": "AkkaDiscovery" } } } } ``` -------------------------------- ### GitHub Actions CI/CD Workflow Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/project-structure/SKILL.md Example GitHub Actions workflow for automating build, pack, and push to NuGet. Uses PowerShell for custom scripts. ```yaml # GitHub Actions example - name: Update version from release notes shell: pwsh run: ./build.ps1 - name: Build run: dotnet build -c Release - name: Pack with tag version run: dotnet pack -c Release /p:PackageVersion=${{ github.ref_name }} - name: Push to NuGet run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json ``` -------------------------------- ### Restore with Detailed Logging Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/package-management/SKILL.md Execute 'dotnet restore --verbosity detailed' to get verbose logging output during the restore process. This can provide more insights into restore failures. ```bash # Restore with detailed logging dotnet restore --verbosity detailed ``` -------------------------------- ### Setup ActivitySource in .NET Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/opentelementry-dotnet-instrumentation/SKILL.md Demonstrates the correct way to initialize ActivitySource instances. Use a primary source for general activities and separate sources for opt-in scenarios, versioning them with SemVer. ```csharp public class MyFeature { // Primary ActivitySource - name typically matches the component or NuGet package name private static readonly ActivitySource ActivitySource = new ("MyApp.MyComponent", "1.0.0"); // Specialized ActivitySource for opt-in scenarios private static readonly ActivitySource DetailedActivitySource = new ("MyApp.MyComponent.Detailed", "1.0.0"); } ``` -------------------------------- ### Install and Configure ReportGenerator for Code Coverage Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs the ReportGenerator tool locally for processing code coverage reports. Usage example shows generating an HTML coverage report. ```bash # ReportGenerator for coverage reports dotnet tool install dotnet-reportgenerator-globaltool ``` ```json "dotnet-reportgenerator-globaltool": { "version": "5.4.1", "commands": ["reportgenerator"], "rollForward": false } ``` ```bash Usage: dotnet reportgenerator -reports:coverage.cobertura.xml -targetdir:coveragereport -reporttypes:Html ``` -------------------------------- ### Runtime vs. Startup Configuration Validation Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/microsoft-extensions-configuration/SKILL.md Illustrates the problem of runtime configuration failures versus the benefit of startup validation. The 'GOOD' example shows how to fail fast with clear error messages. ```csharp // BAD: Fails at runtime when someone tries to use the service public class EmailService { public EmailService(IOptions options) { var settings = options.Value; // Throws NullReferenceException 10 minutes into production _client = new SmtpClient(settings.Host, settings.Port); } } // GOOD: Fails at startup with clear error // "SmtpSettings validation failed: Host is required" ``` -------------------------------- ### Organized DI Registrations with Extension Methods (Good Practice) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/microsoft-extensions-dependency-injection/SKILL.md Demonstrates a clean and composable Program.cs using extension methods to group related service registrations. ```csharp // GOOD: Clean, composable Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services .AddUserServices() .AddOrderServices() .AddEmailServices() .AddPaymentServices() .AddValidators(); var app = builder.Build(); ``` -------------------------------- ### Install and Configure Incrementalist for Incremental Builds Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs the Incrementalist tool locally for optimizing build times by only building changed projects. Usage example shows identifying projects affected by changes. ```bash # Incrementalist - build only changed projects dotnet tool install incrementalist.cmd ``` ```json "incrementalist.cmd": { "version": "1.2.0", "commands": ["incrementalist"], "rollForward": false } ``` ```bash Usage: # Get projects affected by changes since main branch incrementalist --branch main ``` -------------------------------- ### App Code: Bind to Options and Initialize SDKs Explicitly Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-configuration/SKILL.md This application code example shows how to bind configuration values to an `IOptions` object and then use those options to initialize an SDK. It explicitly avoids referencing Aspire client packages or using service discovery. ```csharp // Api/Program.cs builder.Services .AddOptions() .BindConfiguration("BlobStorage") .ValidateDataAnnotations() .ValidateOnStart(); builder.Services.AddSingleton(sp => { var options = sp.GetRequiredService>().Value; return new S3BlobStorageService(options); // uses explicit options only }); ``` -------------------------------- ### Configure AppHost with Postgres and Migrations Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/efcore-patterns/SKILL.md Sets up a distributed application with a PostgreSQL database, a migration service that waits for the database, and an API service that waits for migrations to complete. ```csharp var builder = DistributedApplication.CreateBuilder(args); var postgres = builder.AddPostgres("postgres"); var db = postgres.AddDatabase("appdb"); // Migrations run first, then exit var migrations = builder.AddProject("migrations") .WaitFor(db) .WithReference(db); // API waits for migrations to complete var api = builder.AddProject("api") .WaitForCompletion(migrations) // Key: waits for migrations to finish .WithReference(db); ``` -------------------------------- ### AppHost: Map Database and Blob Storage Resources to Config Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-configuration/SKILL.md This AppHost example demonstrates mapping a PostgreSQL database and a MinIO blob storage container to explicit configuration keys. The API project references these resources and injects their connection details and credentials as environment variables. The API project itself only binds to `Configuration` values. ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); var postgres = builder.AddPostgres("postgres"); var db = postgres.AddDatabase("appdb"); var minio = builder.AddContainer("minio", "minio/minio") .WithArgs("server", "/data") .WithHttpEndpoint(targetPort: 9000, name: "http") .WithHttpEndpoint(targetPort: 9001, name: "console") .WithEnvironment("MINIO_ROOT_USER", "minioadmin") .WithEnvironment("MINIO_ROOT_PASSWORD", "minioadmin"); var api = builder.AddProject("api") .WithReference(db, "Postgres") .WithEnvironment("BlobStorage__Enabled", "true") .WithEnvironment("BlobStorage__ServiceUrl", minio.GetEndpoint("http")) .WithEnvironment("BlobStorage__AccessKey", "minioadmin") .WithEnvironment("BlobStorage__SecretKey", "minioadmin") .WithEnvironment("BlobStorage__Bucket", "attachments") .WithEnvironment("BlobStorage__ForcePathStyle", "true"); builder.Build().Run(); ``` -------------------------------- ### Install Local .NET Tools Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Installs .NET tools into the local repository manifest. You can install a specific version or from a custom NuGet feed. ```bash # Install a tool locally dotnet tool install docfx # Install specific version dotnet tool install docfx --version 2.78.3 # Install from a specific source dotnet tool install MyTool --add-source https://mycompany.pkgs.visualstudio.com/_packaging/feed/nuget/v3/index.json ``` -------------------------------- ### Install Playwright Browsers Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/playwright-blazor/SKILL.md Run this command in PowerShell to install the necessary Playwright browsers and dependencies for your tests. ```bash pwsh -Command "playwright install --with-deps" ``` -------------------------------- ### Test Database Initialization and Access Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-integration-testing/advanced-patterns.md Demonstrates how to retrieve a database connection string from an Aspire resource and perform a basic query to verify initialization. Requires Dapper for QuerySingleAsync. ```csharp public class DatabaseIntegrationTests { private readonly AspireAppFixture _fixture; public DatabaseIntegrationTests(AspireAppFixture fixture) { _fixture = fixture; } [Fact] public async Task Database_ShouldBeInitialized() { // Get connection string from Aspire var dbResource = _fixture.App.GetResource("yourdb"); var connectionString = await dbResource .GetConnectionStringAsync(); // Test database access await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); var result = await connection.QuerySingleAsync( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES"); Assert.True(result > 0, "Database should have tables"); } } ``` -------------------------------- ### Introduce Read Before Write Deployment Pattern Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/serialization/SKILL.md Illustrates a two-phase deployment strategy for introducing new serialization formats, prioritizing deserialization support before enabling serialization. ```csharp // Phase 1: Add deserializer (deployed everywhere) public Order Deserialize(byte[] data, string manifest) => manifest switch { "Order.V1" => DeserializeV1(data), "Order.V2" => DeserializeV2(data), // NEW - can read V2 _ => throw new NotSupportedException() }; // Phase 2: Enable serializer (next release, after V1 deployed everywhere) public (byte[] data, string manifest) Serialize(Order order) => _useV2Format ? (SerializeV2(order), "Order.V2") : (SerializeV1(order), "Order.V1"); ``` -------------------------------- ### GitHub Actions Workflow for .NET Tools Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md This GitHub Actions workflow demonstrates how to set up .NET, restore local tools, build, test with coverage, and generate reports. ```yaml jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: global-json-file: global.json - name: Restore tools run: dotnet tool restore - name: Build run: dotnet build - name: Test with coverage run: dotnet test --collect:"XPlat Code Coverage" - name: Generate coverage report run: dotnet reportgenerator -reports:**/coverage.cobertura.xml -targetdir:coveragereport - name: Build documentation run: dotnet docfx docs/docfx.json ``` -------------------------------- ### Install ReportGenerator Global Tool Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/crap-analysis/SKILL.md Install the ReportGenerator tool globally using the .NET CLI. This makes the 'reportgenerator' command available system-wide. ```bash dotnet tool install --global dotnet-reportgenerator-globaltool ``` -------------------------------- ### Install and Run Slopwatch in Azure Pipelines Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/slopwatch/SKILL.md This snippet shows how to install the Slopwatch global tool and run an analysis as part of an Azure Pipelines build. ```yaml - task: DotNetCoreCLI@2 displayName: 'Install Slopwatch' inputs: command: 'custom' custom: 'tool' arguments: 'install --global Slopwatch.Cmd' - script: slopwatch analyze -d . --fail-on warning displayName: 'Slopwatch Analysis' ``` -------------------------------- ### Scrub Dynamic Values Consistently Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/snapshot-testing/SKILL.md Ensure that dynamic values like GUIDs are consistently scrubbed using `VerifierSettings.ScrubMembersWithType()` to maintain stable snapshots. ```csharp VerifierSettings.ScrubMembersWithType(); ``` -------------------------------- ### Initialize .NET Local Tools Manifest Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md Creates the `.config/dotnet-tools.json` file to manage local tools. This is the first step in setting up local tooling for a repository. ```bash dotnet new tool-manifest ``` -------------------------------- ### Install Playwright Browsers on Cache Miss (GitHub Actions) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/playwright-ci-caching/SKILL.md Installs Playwright browsers only if the cache was not hit, using a PowerShell script. This ensures browsers are downloaded only when necessary. ```yaml - name: Install Playwright Browsers if: steps.playwright-cache.outputs.cache-hit != 'true' shell: pwsh run: ./build/playwright.ps1 install --with-deps ``` -------------------------------- ### Install Playwright Browsers on Cache Miss (Azure DevOps) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/playwright-ci-caching/SKILL.md Installs Playwright browsers using a PowerShell script if the cache was not hit, indicated by the 'PlaywrightCacheHit' variable in Azure DevOps. ```yaml - task: PowerShell@2 displayName: 'Install Playwright Browsers' condition: ne(variables['PlaywrightCacheHit'], 'true') inputs: filePath: 'build/playwright.ps1' arguments: 'install --with-deps' ``` -------------------------------- ### Complete Development Setup with Local Tools Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/local-tools/SKILL.md This JSON defines local .NET tools with specific versions and configurations, including docfx, dotnet-ef, and reportgenerator. The accompanying bash commands show the development workflow. ```json { "version": 1, "isRoot": true, "tools": { "docfx": { "version": "2.78.3", "commands": ["docfx"], "rollForward": false }, "dotnet-ef": { "version": "9.0.0", "commands": ["dotnet-ef"], "rollForward": false }, "dotnet-reportgenerator-globaltool": { "version": "5.4.1", "commands": ["reportgenerator"], "rollForward": false }, "csharpier": { "version": "0.30.3", "commands": ["dotnet-csharpier"], "rollForward": false }, "incrementalist.cmd": { "version": "1.2.0", "commands": ["incrementalist"], "rollForward": false } } } ``` ```bash # Initial setup dotnet tool restore # Format code before commit dotnet csharpier . # Run tests with coverage dotnet test --collect:"XPlat Code Coverage" dotnet reportgenerator -reports:**/coverage.cobertura.xml -targetdir:coverage # Build documentation dotnet docfx docs/docfx.json # Check which projects changed (for large repos) incrementalist --branch main ``` -------------------------------- ### Register and Validate Options at Startup Source: https://context7.com/aaronontheweb/dotnet-skills/llms.txt Register options with configuration binding and data annotation validation. Use ValidateOnStart() to ensure validation occurs at application startup. ```csharp builder.Services.AddOptions() .BindConfiguration(SmtpSettings.SectionName) .ValidateDataAnnotations() .ValidateOnStart(); // CRITICAL: without this, validation only runs on first access ``` -------------------------------- ### Install .NET Dev Cert to System Trust (Ubuntu/Debian) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/dotnet-devcert-trust/SKILL.md Manually installs a .NET development certificate into the system's trusted certificate store on Debian-based systems. This involves copying the certificate and updating the CA certificate bundle. ```bash sudo cp /tmp/dotnet-dev-cert.crt /usr/local/share/ca-certificates/dotnet-dev-cert.crt sudo chmod 644 /usr/local/share/ca-certificates/dotnet-dev-cert.crt sudo update-ca-certificates ``` -------------------------------- ### Configure Respawn Options for Database Reset Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/testcontainers/infrastructure-patterns.md Shows how to configure Respawn with specific options, including tables to ignore, schemas to include/exclude, the database adapter, and whether to reseed. ```csharp var respawner = await Respawner.CreateAsync(connectionString, new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory", new Table("public", "lookup_data"), }, SchemasToInclude = new[] { "public", "app" }, SchemasToExclude = new[] { "audit", "logging" }, DbAdapter = DbAdapter.Postgres, WithReseed = true }); ``` -------------------------------- ### Slopwatch Command-Line Interface Quick Reference Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/slopwatch/SKILL.md This section provides common Slopwatch CLI commands for initial setup, running analysis, enabling strict mode, viewing statistics, updating baselines, and outputting results in JSON format. ```bash # First time setup slopwatch init git add .slopwatch/baseline.json # After every LLM code change slopwatch analyze # Strict mode (recommended) slopwatch analyze --fail-on warning # With stats (performance debugging) slopwatch analyze --stats # Update baseline (rare, document why) slopwatch analyze --update-baseline # JSON output for tooling slopwatch analyze --output json ``` -------------------------------- ### AOT-Compatible MessagePack Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/serialization/SKILL.md Configure MessagePack for Ahead-of-Time (AOT) compilation using source generators and a composite resolver. ```csharp // Use source generator for AOT [MessagePackObject] public partial class Order { } // partial enables source gen // Configure resolver var options = MessagePackSerializerOptions.Standard .WithResolver(CompositeResolver.Create( GeneratedResolver.Instance, // Generated StandardResolver.Instance)); ``` -------------------------------- ### PostgreSQL Integration Test Setup Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/testcontainers/database-patterns.md Sets up a PostgreSQL container for integration tests, including environment variables for credentials and database name. The connection string is dynamically generated based on the mapped port. ```csharp public class PostgreSqlTests : IAsyncLifetime { private readonly TestcontainersContainer _dbContainer; private NpgsqlConnection _connection; public PostgreSqlTests() { _dbContainer = new TestcontainersBuilder() .WithImage("postgres:latest") .WithEnvironment("POSTGRES_PASSWORD", "postgres") .WithEnvironment("POSTGRES_DB", "testdb") .WithPortBinding(5432, true) .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(5432)) .Build(); } public async Task InitializeAsync() { await _dbContainer.StartAsync(); var port = _dbContainer.GetMappedPublicPort(5432); var connectionString = $"Host=localhost;Port={port};Database=testdb;Username=postgres;Password=postgres"; _connection = new NpgsqlConnection(connectionString); await _connection.OpenAsync(); // Create schema await _connection.ExecuteAsync(@" CREATE TABLE orders ( id SERIAL PRIMARY KEY, customer_id VARCHAR(50) NOT NULL, total NUMERIC(10,2) NOT NULL, created_at TIMESTAMP DEFAULT NOW() )"); } public async Task DisposeAsync() { await _connection.DisposeAsync(); await _dbContainer.DisposeAsync(); } [Fact] public async Task PostgreSql_ShouldHandleTransactions() { using var transaction = await _connection.BeginTransactionAsync(); await _connection.ExecuteAsync( "INSERT INTO orders (customer_id, total) VALUES (@CustomerId, @Total)", new { CustomerId = "CUST1", Total = 100.00m }, transaction); await transaction.RollbackAsync(); var count = await _connection.QuerySingleAsync( "SELECT COUNT(*) FROM orders"); Assert.Equal(0, count); // Rollback should prevent insert } } ``` -------------------------------- ### Add MailKit NuGet Package Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/aspire-mailpit-integration/SKILL.md Install the MailKit NuGet package to enable SMTP client functionality for sending emails. ```bash dotnet add package MailKit ``` -------------------------------- ### Enable Central Package Management (CPM) Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/package-management/SKILL.md Create a `Directory.Packages.props` file in the solution root to enable CPM. This file centralizes package versions and can be configured with package definitions. ```xml true ``` -------------------------------- ### Create New .slnx Solution Source: https://github.com/aaronontheweb/dotnet-skills/blob/master/skills/project-structure/SKILL.md Create a new .NET solution file. For .NET 10+, .slnx is the default. For .NET 9, explicitly specify the '--format slnx' option. Projects can then be added using 'dotnet sln add'. ```bash # .NET 10+: Creates .slnx by default dotnet new sln --name MySolution # .NET 9: Specify the format explicitly dotnet new sln --name MySolution --format slnx # Add projects (works the same for both formats) dotnet sln add src/MyApp/MyApp.csproj ```