Skip to main content

Use DevExpress .NET Products in Popular Continuous Integration Systems

  • 9 minutes to read

Important

This help topic applies to DevExpress .NET products only. If you are using the DevExtreme product line, refer to the following article: DevExtreme - Deployment and Continuous Integration.

Notes on Licensing

DevExpress license information must be available during the build stage so it can be injected into binary artifacts. To make that information available in CI/CD environments, store your license key in a text file or an environment variable named DevExpress_License. Examples below demonstrate how you can do this.

Note that license information is sensitive and should be treated as a secret. You may want to store the key in a storage with additional security and access control capabilities (such as Azure Key Vault or AWS Secret Manager).

For information on how to obtain your License Key, review the following help topic: License Key for DevExpress Products.

Important

Use the exact casing (DevExpress_License.txt, DevExpress_LicensePath, DevExpress_License) to avoid license activation issues. On most Unix-like systems, file and environment variable names are case-sensitive.

For example, a macOS development machine or Linux-based CI/CD pipeline will not activate the DevExpress license if the environment variable is named DEVEXPRESS_LICENSE or devexpress_license.

NuGet.org vs NuGet.DevExpress.com Feed

If you are using DevExpress v25.1+, obtain DevExpress NuGet packages from NuGet.org.

If you are using DevExpress v24.2 or earlier, use your personal DevExpress NuGet feed. For additional information, see documentation for an appropriate version: Install DevExpress v24.2 via a NuGet Feed.

Note

If you plan on using a NuGet.org feed, make sure the feed is available:

  • Register the required NuGet.org feed in nuget.config.
  • Make certain that nuget.config is accessible from your build server.

Azure DevOps

Restore DevExpress NuGet Packages

Make sure Nuget.config includes nuget.org as a source:

<?xml version="1.0" encoding="utf-8"?>
  <configuration>
    <packageSources>
      <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    </packageSources>
  </configuration>

Add a new build pipeline.

Add a new NuGet restore task to the pipeline and configure it to work with NuGet.config. You should specify the following settings:

Settings Values
Command restore
Feeds to use Feeds in my NuGet.config
Path to NuGet.config Path to your NuGet.config file

Specify Your .NET License Key

Your .NET License Key must be available at the project build stage (dotnet build / MSBuild). The following two storage options are available:

Note

This is the recommended option. A single file will supply license information to all projects and their associated tasks within a given pipeline. If you use a file storage, you avoid possible build server caching issues that make a trial version message persist. (The dotnet publish command always rebuilds the project unless the --no-build flag is specified.)

Locate your pipeline and select Pipeline | Library | Secure files. Upload DevExpress_License.txt. For additional information, see Use secure files. During pipeline execution, the file must exist at the following path.

Windows: %AppData%/DevExpress/

Linux: $HOME/.config/DevExpress/

macOS: $HOME/Library/Application Support/DevExpress/

Azure DevOps - Add Secure File

- task: DownloadSecureFile@1
  name: dxLicense
  inputs:
    secureFile: 'DevExpress_License.txt'

- task: PowerShell@2
  displayName: 'Obtain DevExpress license file'
  inputs:
    targetType: 'inline'
    pwsh: true
    script: |
      $src = '$(dxLicense.secureFilePath)'
      ## Windows runner
      # $basePath = Join-Path $env:APPDATA 'DevExpress'
      ## Linux runner
      # $basePath = Join-Path $env:HOME '.config/DevExpress'
      ## macOS runner
      # $basePath = Join-Path $HOME 'Library/Application Support/DevExpress'

      New-Item -ItemType Directory -Path $basePath -Force | Out-Null

      $licensePath = Join-Path $basePath 'DevExpress_License.txt'
      Copy-Item -LiteralPath $src -Destination $licensePath -Force

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

GitHub Actions

Create a secret with your DevExpress NuGet credentials for CI/CD operations. You must be the repository owner to create secrets for an environment in a personal account.

Navigate to the main page of the repository and click Settings.

Access Settings in GitHub

In the Security section of the sidebar, select Secrets and variables | Actions. Click New repository secret in the Secrets tab.

Add a secret with your personal .NET License Key.

GitHub - Add Secret with DevExpress License Key

Use the secret value in your GitHub Actions CLI scripts (YAML). Assign the license key to the environment variable named DevExpress_License. Note that GitHub Actions can only read a secret if you explicitly include the secret in a workflow. Enclose the secret’s name within the quoting rules when you pass a secret in the command line. This is required to avoid special characters that may affect your shell.

jobs:
  build:
    # ...
    env:
      DevExpress_License: ${{ secrets.DevExpressPipelineVariable }}
    # ...
    steps:
      - name: Register NuGet.org Source
        run: dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org

Refer to the following article for more information on how to use secrets in the GitHub workflow: Using secrets in a workflow.

Sample YAML file
name: .NET Core Desktop

on:
 push:
   branches: [ "main" ]
 pull_request:
   branches: [ "main" ]

jobs:

 build:

   strategy:
     matrix:
       configuration: [Debug]

   runs-on: windows-latest  

   env:
     DevExpress_License: ${{ secrets.DevExpressPipelineVariable }}
     Solution_Name: your-solution-name                         
     Test_Project_Path: your-test-project-path                 
     Wap_Project_Directory: your-wap-project-directory-name    
     Wap_Project_Path: your-wap-project-path                   

   steps:
   - name: Checkout
     uses: actions/checkout@v4
     with:
       fetch-depth: 0

   # Add DevExpress license file
   #- name: AddDevExpressLicense
   #  shell: cmd
   #  run: |
   #    set "SRC=%GITHUB_WORKSPACE%\DevExpress_License.txt"
   #    set "DEST=%APPDATA%\DevExpress"
   #    if not exist "%DEST%" mkdir "%DEST%"
   #    copy "%SRC%" "%DEST%" /Y

   # Add DevExpress license file
   - name: AddDevExpressLicense
     shell: cmd
     run: |
       set "DEST=%APPDATA%\DevExpress"
       if not exist "%DEST%" mkdir "%DEST%"
       echo "${{ secrets.DevExpressPipelineVariable }}" > %APPDATA%\DevExpress\DevExpress_License.txt

   # Install the .NET Core workload
   - name: Install .NET Core
     uses: actions/setup-dotnet@v4
     with:
       dotnet-version: 8.0.x

   # Add local NuGet source
     - name: Register NuGet.org Source
       run: dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org
       shell: cmd

   # Restore
   - name: Restore
     run: dotnet restore ./Sample

   # Build
   - name: Build
     run: dotnet build ./Sample --disable-build-servers

   # Run app to generate image
   - name: Run
     run: dotnet run --project ./Sample/DashboardCICDExport.csproj

   # Upload PNG artifact
   - name: Upload 
     uses: actions/upload-artifact@v4
     with:
       name: generated-image
       path: .\output.png

Note

.NET build keeps its infrastructure processes in memory after a project build is complete. This process cache optimizes performance for successive build operations. The example above explicitly disables caching. Such configuration prevents rare situations where DevExpress trial warnings persist even though license variable mapping is present for the build or publish task.

GitLab

Open your project CI/CD settings (Settings > CI/CD):

GitLab - Open Project CI/CD Settings

Next to Variables, first click Expand, then Add variable.

GitLab - Add Variable

Specify a project variable (available to all jobs in a pipeline) to store your personal .NET License Key:

Important

  • Select the Masked option.
  • Variables defined in this way are available globally for every pipeline and its jobs.

GitLab - Specify Variable Parameters

Write the secret’s value to a file:

- name: Create a file with the DevExpress license key
  shell: pwsh
  env:
    tempEnvVariable: ${{ secrets.DevExpressPiplelineVariable }}
  run: |
    ## Windows runner
    # $basePath = Join-Path $env:APPDATA 'DevExpress'
    ## Linux runner
    # $basePath = Join-Path $env:HOME '.config/DevExpress'
    ## macOS runner
    # $basePath = Join-Path $HOME 'Library/Application Support/DevExpress'

    New-Item -ItemType Directory -Path $basePath -Force | Out-Null

    $licensePath = Join-Path $basePath 'DevExpress_License.txt'
    $env:tempEnvVariable | Set-Content -Path $licensePath -Encoding UTF8

TeamCity

Create a new “Password” parameter. For instructions, see Create and Set Up Custom Parameters.

TeamCity - Create Password Parameter

Create a new Build Step before building and publishing the project. Configure the Build Step as follows:

  • Runner: PowerShell
  • Script execution mode: Execute .ps1 script from external file
  • Script: Source code
  • Script source: Use the following code snippet to specify the inline script
# TeamCity password parameter
$license = "%parameter1%"

## Windows runner
# $basePath = Join-Path $env:APPDATA 'DevExpress'
## Linux runner
# $basePath = Join-Path $env:HOME '.config/DevExpress'
## macOS runner
# $basePath = Join-Path $HOME 'Library/Application Support/DevExpress'

$licensePath  = Join-Path $basePath "DevExpress_License.txt"
New-Item -ItemType Directory -Force -Path $basePath | Out-Null
Set-Content -Path $licensePath -Value $license -Encoding UTF8
See Also