C# (.NET Core) application
You can build and test a C# and .NET Core application using a Linux or Windows platform on Harness Cloud or a self-hosted Kubernetes cluster build infrastructure.
This guide assumes you've created a Harness CI pipeline. For more information about creating pipelines, go to:
If you don't have a Harness account yet, you can create one for free at app.harness.io.
Specify architecture
You can use a Linux or Windows platform to build and test C# (.NET Core) apps. These examples use Linux build infrastructure.
- Harness Cloud
- Self-hosted
stages:
- stage:
name: build
identifier: build
type: CI
spec:
cloneCodebase: true
platform:
os: Linux
arch: Amd64 ## Can be Amd64 or Arm64
runtime:
type: Cloud
spec: {}
There are several self-hosted build infrastructure options. This example uses a Kubernetes cluster build infrastructure.
stages:
- stage:
name: build
identifier: build
description: ""
type: CI
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR_ID
namespace: YOUR_NAMESPACE
automountServiceAccountToken: true
nodeSelector: {}
os: Linux
Install dependencies
- Harness Cloud
- Self-hosted
The .NET Core SDK and other .NET libraries are pre-installed on Harness Cloud runners. For details about all available tools and versions, go to Platforms and image specifications. You can use Run steps to install additional dependencies or run dotnet restore
.
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
shell: Sh
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
You can use Run steps to install dependencies or run commands such as dotnet restore
.
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
Cache dependencies
Add caching to your Build (CI
) stage.
- Harness Cloud
- Self-hosted
Cache your .NET dependencies with Cache Intelligence. Add caching to your stage.spec
:
- stage:
spec:
caching:
enabled: true
key: cache-{{ checksum "packages.lock.json" }}
paths:
- "~/.local/share/NuGet/cache"
sharedPaths:
- ~/.local/share/NuGet/cache
With self-hosted build infrastructures, you can:
YAML example: Save and restore cache steps
Here's an example of a pipeline with Save Cache to S3 and Restore Cache from S3 steps.
steps:
- step:
type: RestoreCacheS3
name: Restore Cache From S3
identifier: Restore_Cache_From_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
archiveFormat: Tar
- step:
type: Run
...
- step:
type: BuildAndPushDockerRegistry
...
- step:
type: SaveCacheS3
name: Save Cache to S3
identifier: Save_Cache_to_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
sourcePaths:
- ~/.local/share/NuGet/cache
archiveFormat: Tar
Build and run tests
Add Run steps to build and run your tests.
- Harness Cloud
- Self-hosted
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Sh
command: |-
dotnet restore
dotnet build --no-restore
dotnet test --no-build --verbosity normal
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Sh
command: |-
dotnet restore
dotnet build --no-restore
dotnet test --no-build --verbosity normal
Visualize test results
You can view test results on the Tests tab of your pipeline executions. Test results must be in JUnit XML format.
You can use a converter to output compatible JUnit XML reports, such as NUnit to JUnit or .NET trx2JUnit.
For your pipeline to produce test reports, you need to modify the Run step that runs your tests. Make sure the command
generates JUnit XML reports and add the reports
specification.
- Harness Cloud
- Self-hosted
- step:
type: Run
identifier: install_converter
name: install converter
spec:
shell: Sh
command: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Sh
command: |-
dotnet restore
dotnet build
dotnet test --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
- step:
type: Run
identifier: install_converter
name: install converter
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Sh
command: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
shell: Sh
command: |-
dotnet restore
dotnet build
dotnet test --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
Run tests with Test Intelligence
Test Intelligence is available for C# (.NET Core), however, it is behind the feature flag TI_DOTNET
. Contact Harness Support to enable the feature.
With this feature flag enabled, you can use Run Tests steps to run unit tests with Test Intelligence.
- Harness Cloud
- Self-Hosted
- step:
type: RunTests
identifier: runTestsWithIntelligence
name: runTestsWithIntelligence
spec:
language: Csharp
buildEnvironment: Core
frameworkVersion: "6.0"
buildTool: Dotnet
args: dotnet test --no-build --verbosity normal
namespaces: aw,fc
runOnlySelectedTests: true
preCommand: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
dotnet restore
dotnet build
postCommand: trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
- step:
type: RunTests
identifier: runTestsWithIntelligence
name: runTestsWithIntelligence
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:6.0
language: Csharp
buildEnvironment: Core
frameworkVersion: "6.0"
buildTool: Dotnet
args: dotnet test --no-build --verbosity normal
namespaces: aw,fc
runOnlySelectedTests: true
preCommand: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
dotnet restore
dotnet build
postCommand: trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
Specify version
- Harness Cloud
- Self-hosted
The .NET SDK is pre-installed on Hosted Cloud runners. For details about all available tools and versions, go to Platforms and image specifications.
If you need a specific .NET Core SDK version that isn't already installed, you can use a Run step to install it, or you can use the setup-dotnet action in a GitHub Action plugin step.
Install one .NET SDK version
- step:
type: Action
name: Install dotnet
identifier: install_dotnet
spec:
uses: actions/setup-dotnet@v3
with:
dotnet-version: '3.1.x'
Install multiple .NET SDK versions
- Add the matrix looping strategy configuration to your stage.
strategy:
matrix:
dotnetVersion:
- 7.0.x
- 5.0.x
- Reference the matrix variable in your steps.
- step:
type: Action
name: Install dotnet
identifier: install_dotnet
spec:
uses: actions/setup-dotnet@v3
with:
dotnet-version: <+matrix.dotnetVersion>
Specify the desired .NET SDK image tag in your steps. There is no need for a separate install step when using Docker.
Use one .NET SDK version
- step:
type: Run
name: dotnet version
identifier: dotnet_version
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Sh
command: |-
dontet --info
Use multiple .NET SDK versions
- Add the matrix looping strategy configuration to your stage.
- stage:
strategy:
matrix:
dotnetVersion:
- 7.0
- 6.0
- Reference the matrix variable in the
image
field of your steps.
- step:
type: Run
name: dotnet Version
identifier: dotnet_version
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:<+stage.matrix.dotnetVersion>
shell: Sh
command: |-
dotnet --info
Full pipeline examples
The following full pipeline examples are based on the partial examples above.
- Harness Cloud
- Self-hosted
If you copy this example, replace the placeholder values with appropriate values for your code repo connector and repository name. Depending on your project and organization, you may also need to replace projectIdentifier
and orgIdentifier
.
YAML example
pipeline:
name: default
identifier: default
projectIdentifier: default
orgIdentifier: default
properties:
ci:
codebase:
connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
repoName: YOUR_REPO_NAME
build: <+input>
tags: {}
stages:
- stage:
name: build
identifier: build
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: true
key: cache-{{ checksum "packages.lock.json" }}
paths:
- "~/.local/share/NuGet/cache"
execution:
steps:
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
shell: Sh
command: |-
dotnet add package Newtonsoft.json --version 12.0.1
- step:
type: Run
identifier: install_converter
name: install converter
spec:
shell: Sh
command: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
shell: Sh
command: |-
dotnet restore
dotnet build
dotnet test --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
sharedPaths:
- ~/.local/share/NuGet/cache
If you copy this example, replace the placeholder values with appropriate values for your code repo connector, Kubernetes cluster connector, Kubernetes namespace, and repository name. Depending on your project and organization, you may also need to replace projectIdentifier
and orgIdentifier
.
YAML example
pipeline:
name: default
identifier: default
projectIdentifier: default
orgIdentifier: default
properties:
ci:
codebase:
connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
repoName: YOUR_REPO_NAME
build: <+input>
tags: {}
stages:
- stage:
name: build
identifier: build
description: ""
type: CI
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR_ID
namespace: YOUR_NAMESPACE
automountServiceAccountToken: true
nodeSelector: {}
os: Linux
execution:
steps:
- step:
type: RestoreCacheS3
name: Restore Cache From S3
identifier: Restore_Cache_From_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
archiveFormat: Tar
- step:
type: Run
name: dotnet version
identifier: dotnet_version
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Sh
command: |-
dontet --info
- step:
type: Run
identifier: dependencies
name: Dependencies
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
command: |-
dotnet add package Newtonsoft.json -- version 12.0.1
- step:
type: Run
identifier: install_converter
name: install converter
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Sh
command: |-
dotnet tool install -g trx2junit
export PATH="$:/root/.dotnet/tools"
- step:
type: Run
identifier: build_dotnet_app
name: Build DotNet App
spec:
connectorRef: account.harnessImage
image: mcr.microsoft.com/dotnet/sdk:7.0
shell: Sh
command: |-
dotnet restore
dotnet build
dotnet test --no-build --verbosity normal
trx2junit results.trx
reports:
type: JUnit
spec:
paths:
- results.xml
- step:
type: SaveCacheS3
name: Save Cache to S3
identifier: Save_Cache_to_S3
spec:
connectorRef: YOUR_AWS_CONNECTOR_ID
region: us-east-1
bucket: YOUR_S3_BUCKET
key: cache-{{ checksum "packages.lock.json" }}
sourcePaths:
- ~/.local/share/NuGet/cache
archiveFormat: Tar
Next steps
Now that you have created a pipeline that builds and tests a C# (.NET Core) app, you could:
- Create triggers to automatically run your pipeline.
- Add steps to build and upload artifacts.
- Add a step to build and push an image to a Docker registry.