When Microsoft announced .Net Core is a cross-platform programming language, C# devs finally felt that their code can be used anywhere. On Azure, we can use different images for building our code we just need to target an image and voila… in theory and hello world apps probably yes. With a production one, hmm let me invite you to my journey.
Yaml schema
The newest approach to create a build on Azure is to prepare a .yaml file with configuration and push it to the repository. We will be using an ubuntu-latest image. If your project contains only .Net Core code everything you need to set is:
- task: DotNetCoreCLI@2 inputs: command: 'build' projects: '$(build.sourcesdirectory)' - task: DotNetCoreCLI@2 inputs: command: publish publishWebProjects: True arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)' zipAfterPublish: True - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.ArtifactStagingDirectory)' artifactName: 'myWebsiteName'
Simply build a project, and then publish to artifact directory. In the end push the drop folder that can be handled by release task. That scenario you will find probably on every tutorial.
Add NPM
If you are using some frontend framework you will probably need to install npm. You just need to find npm in the toolbar, then provide a proper script:
Yaml will look like this:
- task: Npm@1 inputs: command: 'install' workingDir: '$(build.sourcesdirectory)' - task: Npm@1 inputs: command: 'custom' workingDir: '$(build.sourcesdirectory)' customCommand: 'run build'
Worth to mention that on the Azure .yaml editor you have a handy intelisense, with errors, warnings, and suggestions.
Migrations
Now we are getting serious, tutorials and Microsoft documentation focus on simple projects mainly without migrations. On the internet, you can find a couple of approaches on how to deal with it. Let me introduce you to my solution:
First, install dotnet ef to use the migration tool and create a sql script with required migrations. Add the code below:
- task: DotNetCoreCLI@2 displayName: Install dotnet-ef inputs: command: 'custom' custom: 'tool' arguments: 'install --global dotnet-ef'
Then use Entity Framework Core Migrations Script Generator from the Visual Studio marketplace. You can use of course custom dotnet ef inline script, that’s doesn’t matter.
With the additional tool .yaml will look like:
- task: efcore-migration-script-generator-task@0 inputs: projectpath: '$(build.sourcesdirectory)/contextProject' startupprojectpath: '$(build.sourcesdirectory)/startProject' databasecontexts: 'Context' targetfolder: '$(build.artifactstagingdirectory)/migrations'
That should work…yes should but probably you will see a problem like that:
Could not execute because the specified command or file was not found. Possible reasons for this include: * You misspelled a built-in dotnet command. * You intended to execute a .NET Core program, but dotnet-ef does not exist. * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.
I’ve spent a couple of hours trying to investigate what was the problem. Even if we install globally (which is not recommended by the .net team) the dotnet ef tool it wouldn’t be found in the PATH correctly. My solution for this is to use a specific version of .Net Core before invoking any commands:
- task: UseDotNet@2 inputs: version: '3.1.200'
Now dotnet ef should be found successfully!
Environment variables
The configuration is one of the hardest things in programming languages, to make it more standardized .Net Core suggests to use environmental variables. It’s a great tool to change the configuration by the Variable store in Azure pipelines (for example a db connection string needed for migrations).
Please remember one crucial rule when using Linux based systems: case sensitive is very important!
If something is working on the Windows machine quite ok, like the dir name is not uppercase or we don’t care about the case of the environment variable when using Linux remember to be more strict about it.
Release
The last thing after a successful build is to make a release. Here you can use Linux agent as well… but to be honest I don’t recommend this option. Why? The majority of tools are written in PowerShell, which can’t be invoked on Linux machines. You have 2 options:
- Write your own bash scripts
- Use Windows Agent for release
Here I’m posting a full .yaml with my build for .Net Core with migrations, I hope it will help someone with proper CI integration.
trigger: branches: include: - master pool: vmImage: 'ubuntu-latest' variables: buildConfiguration: 'Debug' steps: - task: UseDotNet@2 inputs: version: '3.1.200' - task: DotNetCoreCLI@2 inputs: command: 'build' projects: '$(buildConfiguration)' - task: Npm@1 inputs: command: 'install' workingDir: '$(build.sourcesdirectory)' - task: Npm@1 inputs: command: 'custom' workingDir: '$(build.sourcesdirectory)' customCommand: 'run build' - task: DotNetCoreCLI@2 displayName: Install dotnet-ef inputs: command: 'custom' custom: 'tool' arguments: 'install --global dotnet-ef' - task: efcore-migration-script-generator-task@0 inputs: projectpath: '$(build.sourcesdirectory)/contextProject' startupprojectpath: '$(build.sourcesdirectory)/startProject' databasecontexts: 'Context' targetfolder: '$(build.artifactstagingdirectory)/migrations' - task: DotNetCoreCLI@2 inputs: command: publish publishWebProjects: True arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)' zipAfterPublish: True # this code takes all the files in $(Build.ArtifactStagingDirectory) and uploads them as an artifact of your build. - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.ArtifactStagingDirectory)' artifactName: 'MyProjectName'