CI/CD for .NET with GitHub Actions: Automate Build, Test, Deploy
Learn to set up CI/CD pipelines for .NET apps using GitHub Actions.
20+ years shipping production .NET services in enterprise systems. Lessons pulled from things that broke in production.
- ✓Basic knowledge of .NET and C#
- ✓A GitHub account and a .NET project in a repository
- ✓Familiarity with YAML syntax
- ✓An Azure subscription (for deployment section)
- GitHub Actions automates building, testing, and deploying .NET apps.
- Define workflows in YAML files in the .github/workflows directory.
- Use setup-dotnet action to install the correct SDK version.
- Run tests with dotnet test and publish with dotnet publish.
- Deploy to Azure Web Apps using azure/webapps-deploy action.
Imagine you're a chef who has to cook a complex meal every time an order comes in. Instead of doing everything by hand, you set up an automated kitchen: a robot chops vegetables, another stirs the pot, and a third plates the dish. CI/CD with GitHub Actions is like that automated kitchen for your code. Every time you push changes to GitHub, it automatically builds your code, runs tests, and deploys it to production—so you don't have to do it manually.
In modern software development, delivering features quickly and reliably is crucial. Continuous Integration and Continuous Deployment (CI/CD) pipelines automate the process of building, testing, and deploying applications. For .NET developers, GitHub Actions provides a powerful, integrated CI/CD platform directly within your repository. This tutorial will guide you through creating a production-ready CI/CD pipeline for a .NET application using GitHub Actions. You'll learn how to set up workflows that build your code, run unit and integration tests, perform security scanning, and deploy to Azure App Service. We'll cover real-world scenarios like handling secrets, caching dependencies, and conditional deployments. By the end, you'll have a robust pipeline that ensures every commit is automatically validated and deployed, reducing manual errors and speeding up your release cycle.
What is GitHub Actions and Why Use It for .NET?
GitHub Actions is a CI/CD platform that allows you to automate your build, test, and deployment pipeline directly from your GitHub repository. For .NET developers, it offers a seamless way to integrate with the .NET CLI and Azure services. You define workflows as YAML files in the .github/workflows directory. Each workflow consists of one or more jobs that run on GitHub-hosted runners (Ubuntu, Windows, macOS) or self-hosted runners. Key benefits include tight integration with GitHub, a large marketplace of pre-built actions, and generous free tier for public repositories. For .NET specifically, you can use actions like setup-dotnet to install the SDK, and azure/webapps-deploy to deploy to Azure App Service.
Setting Up Your First .NET CI Pipeline
Let's create a CI pipeline that builds and tests a .NET application on every push. Start by creating a file named .github/workflows/ci.yml in your repository. The workflow will checkout the code, install the .NET SDK, restore dependencies, build, and run tests. Use the actions/checkout action to fetch your repository. The setup-dotnet action installs the specified .NET SDK version. The dotnet restore command restores NuGet packages. Then dotnet build compiles the project, and dotnet test runs unit tests. You can also add caching for NuGet packages to speed up subsequent runs.
Adding Code Quality and Security Scanning
Beyond building and testing, you should integrate code quality checks and security scanning into your pipeline. Tools like SonarCloud, CodeQL, and .NET's built-in analyzers can catch issues early. For example, you can run dotnet format to check code style, or use the github/codeql-action to perform security analysis. Add a step to run dotnet format --verify-no-changes to enforce formatting. For security, use the CodeQL action to analyze your code for vulnerabilities. You can also integrate with Snyk or Dependabot for dependency scanning.
Deploying to Azure App Service
Once your code passes CI, you can automatically deploy to Azure App Service. The azure/webapps-deploy action simplifies this. First, create an Azure Web App and configure deployment credentials. In your GitHub repository, add the publish profile as a secret (e.g., AZURE_WEBAPP_PUBLISH_PROFILE). Then, in your workflow, add a deploy job that depends on the build job. Use the action to publish the build artifacts and deploy them. You can also use slot deployments for zero-downtime updates.
Handling Environment-Specific Configurations
In real-world applications, you need different configurations for development, staging, and production. Use environment variables and secrets to manage these. In GitHub Actions, you can define environment-specific variables and secrets in the repository settings. Then reference them in your workflow using ${{ vars.VARIABLE_NAME }} for variables and ${{ secrets.SECRET_NAME }} for secrets. For .NET, you can use the appsettings.{Environment}.json pattern and set the ASPNETCORE_ENVIRONMENT variable in the workflow. For example, set ASPNETCORE_ENVIRONMENT: Production in the deploy job.
Advanced: Matrix Builds and Conditional Steps
To test your application across multiple .NET versions or operating systems, use matrix builds. Define a matrix strategy in your job to run the same steps with different parameters. You can also add conditional steps using the 'if' keyword. For example, only run deployment on the main branch, or skip certain steps for pull requests. Matrix builds are useful for ensuring compatibility.
Best Practices and Security Considerations
When setting up CI/CD pipelines, follow security best practices: use least privilege for service principals, rotate secrets regularly, and audit workflow runs. For GitHub Actions, avoid using self-hosted runners for public repositories unless necessary. Use OpenID Connect (OIDC) to authenticate to cloud providers instead of long-lived secrets. For .NET, enable NuGet package signing verification and use lock files. Also, consider adding a manual approval step for production deployments using GitHub Environments with required reviewers.
The Silent Build Failure: When a NuGet Package Update Broke CI
- Always use package lock files to ensure reproducible builds.
- Include integration tests that cover the application startup and key dependencies.
- Pin dependency versions in production pipelines to avoid unexpected updates.
- Run CI on a clean environment (e.g., fresh VM) to catch environment-specific issues.
- Monitor build logs for warnings that could indicate breaking changes.
uses: actions/setup-dotnet@v3with: dotnet-version: '6.0.x'| File | Command / Code | Purpose |
|---|---|---|
| basic-workflow.yml | name: .NET CI | What is GitHub Actions and Why Use It for .NET? |
| .github | name: CI | Setting Up Your First .NET CI Pipeline |
| .github | - name: Check code formatting | Adding Code Quality and Security Scanning |
| .github | name: Deploy to Azure | Deploying to Azure App Service |
| .github | - name: Deploy to Azure Web App | Handling Environment-Specific Configurations |
| .github | jobs: | Advanced |
| .github | jobs: | Best Practices and Security Considerations |
Key takeaways
Common mistakes to avoid
4 patternsNot specifying the .NET SDK version in setup-dotnet, causing builds to use a different version than local.
Hardcoding secrets in the workflow file.
Running tests without building first.
Not using caching for NuGet packages, causing long restore times.
Interview Questions on This Topic
Explain the structure of a GitHub Actions workflow file.
Frequently Asked Questions
20+ years shipping production .NET services in enterprise systems. Lessons pulled from things that broke in production.
That's ASP.NET. Mark it forged?
3 min read · try the examples if you haven't