C# (.NET Core)
You can build and test a C# and .NET Core application using a Linux or Windows platform on Harness Cloud or a self-managed Kubernetes cluster build infrastructure.
This guide assumes you've created a Harness CI pipeline.
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-managed
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-managed 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-managed
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: YOUR_IMAGE_REGISTRY_CONNECTOR
      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.
- Cache Intelligence
- Save and Restore Cache steps
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
You can use built-in steps to:
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-managed
- 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: YOUR_IMAGE_REGISTRY_CONNECTOR
      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-managed
- step:
    type: Run
    identifier: install_converter
    name: install converter
    spec:
      shell: Sh
      command: |-
        dotnet tool install -g trx2junit
        export PATH="$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: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      shell: Sh
      command: |-
        dotnet tool install -g trx2junit
        export PATH="$PATH:/root/.dotnet/tools"
- step:
    type: Run
    identifier: build_dotnet_app
    name: Build DotNet App
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      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 on C# codebases.
- Harness Cloud
- Self-managed
- step:
    type: RunTests
    identifier: runTestsWithIntelligence
    name: runTestsWithIntelligence
    spec:
      language: Csharp
      buildEnvironment: Core
      frameworkVersion: "6.0"
      buildTool: Dotnet
      args: --no-build --verbosity normal ## Equivalent to 'dotnet test --no-build --verbosity normal' in a Run step or shell.
      namespaces: aw,fc
      runOnlySelectedTests: true
      preCommand: |-
        dotnet tool install -g trx2junit
        export PATH="$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: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:6.0
      language: Csharp
      buildEnvironment: Core
      frameworkVersion: "6.0"
      buildTool: Dotnet
      args: --no-build --verbosity normal ## Equivalent to 'dotnet test --no-build --verbosity normal' in a Run step or shell.
      namespaces: aw,fc
      runOnlySelectedTests: true
      preCommand: |-
        dotnet tool install -g trx2junit
        export PATH="$PATH:/root/.dotnet/tools"
        dotnet restore
        dotnet build
      postCommand: trx2junit results.trx
      reports:
        type: JUnit
        spec:
          paths:
            - results.xml
Test splitting
Harness CI supports test splitting (parallelism) for both Run and Run Tests steps.
Specify version
- Harness Cloud
- Self-managed
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 step. On Windows platforms, you might also need to run the setup-msbuild action. On Windows platforms, you might also need to run the setup-msbuild action.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"- step:
    type: Action
    name: Install dotnet
    identifier: install_dotnet
    spec:
      uses: actions/setup-msbuild@v1
      with: ## Optional. Specify a specific version of visual Studio if you have multiple versions installed.
        vs-version: "16.4"Install multiple .NET SDK versions
strategy:
  matrix:
    dotnetVersion:
      - 7.0.x
      - 5.0.x
- step:
    type: Action
    name: Install dotnet
    identifier: install_dotnet
    spec:
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: <+matrix.dotnetVersion>- step:
    type: Action
    name: Install dotnet
    identifier: install_dotnet
    spec:
      uses: actions/setup-msbuild@v1
      with: ## Optional. Specify a specific version of visual Studio if you have multiple versions installed.
        vs-version: "16.4"
Specify the desired .NET SDK image tag in your steps. There is no need for a separate install step when using Docker. On Windows platforms, you might also need to install Microsoft Build Tools into the container. On Windows platforms, you might also need to install Microsoft Build Tools into the container.Use one .NET SDK version
- step:
    type: Run
    name: dotnet version
    identifier: dotnet_version
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: mcr.microsoft.com/dotnet/sdk:7.0
      shell: Sh
      command: |-
        dontet --infoUse multiple .NET SDK versions
- stage:
    strategy:
      matrix:
        dotnetVersion:
          - 7.0
          - 6.0
image field of your steps.- step:
    type: Run
    name: dotnet Version
    identifier: dotnet_version
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      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-managed
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="$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: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: mcr.microsoft.com/dotnet/sdk:7.0
                    shell: Sh
                    command: |-
                      dontet --info
              - step:
                  type: Run
                  identifier: dependencies
                  name: Dependencies
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    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: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: mcr.microsoft.com/dotnet/sdk:7.0
                    shell: Sh
                    command: |-
                      dotnet tool install -g trx2junit
                      export PATH="$PATH:/root/.dotnet/tools"
              - step:
                  type: Run
                  identifier: build_dotnet_app
                  name: Build DotNet App
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    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.