Building and Packaging .NET Core with AppVeyor

1 -> Experimenting with the Kudu API

2 -> Building and Packaging .NET Core with AppVeyor

3 -> Parsing command line arguments in .NET Core

I’ve been working on a project called k-scratch which allows remote logging and file sync with Kudu based sites – mainly for making local editing of Azure Functions easier.

As part of that I broke out the log stream component (called KScratchLog) in to a standalone console app. I plan to make this in to a broader console app that can get, push, log stream etc all from the command prompt… but before any of that can happen I figured I should get some CI going.

I decided on AppVeyor because it has .NET Core support, is free and works well with GitHub (like super well).

AppVeyor allows you to run PowerShell and CMD scripts, and the environments that builds are run in will be familiar to most .NET developers.

Most of the heavy lifting and config is done by placing an AppVeyor.yml script in the root of your GitHub Repo.

I had a hunt around, and saw that some projects use custom build scripts with AppVeyor in conjunction with the yml file, but I wanted to try and do it all in the yml.

Searching I found an example yml file by Steven Liekens that I used as a starting point.

Setting up the project.json files

I created my project in Visual Studio. It has a console app and a series of portable projects that are .NET Standard 1.3 based.

The first thing I had to do before I could get it to build on the command line using dotnet build was reference the dependency projects in the project.json file. Visual Studio did not do this automatically as it relies on the references in the .xproj files.

"dependencies": {
"Autofac": "4.1.0",
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0",
"System.IO": "4.1.0",
"System.Xml.XmlSerializer": "4.0.11",
"KScratch.Entity": {
"target": "project"
},
"KScratch.Contract": {
"target": "project"
}

The next step was making sure the build outputted .exe files, which it doesn’t by default. This is done in project.json.

Scott Hanselman’s post on self contained apps in .NET Core was a handy reference for this.

"runtimes": {
"win7-x64": {},
"osx.10.10-x64": {},
"ubuntu.14.04-x64": {}
}

Also make sure you reference the portable projects here too:

"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1"
},
"KScratch.Contract": {
"target": "project"
},
"KScratch.Entity": {
"target": "project"
},
"KScratch.Portable": {
"target": "project"
}
}
}

The final part of the story was getting the build to work. I played around on the command line on my local machine first to get it going before transporting the commands in to the build_script section of the AppVeyor.yml file.

I also added the ability to build separate platforms in the script, for now only windows is present.

Worth noting is that the AppVeyor platform would not support win10-x64 so I had to change it to win7-x64.

Once the build is completed and dotnet publish is called I package up the file using 7z, before referencing that zip as an artefact.

You can see a sample build output here and the resulting artefact here.

Finally – I went to the AppVeyor settings and got the MD for the all important AppVeyor build status badge and inserted it in my readme.md file!

Build status

Full AppVeyor.yml listing from here

version: '1.0.{build}'
configuration:
- Release
platform:
- win7-x64
environment:
  # Don't report back to the mothership
  DOTNET_CLI_TELEMETRY_OPTOUT: 1
init:
- ps: $Env:LABEL = "CI" + $Env:APPVEYOR_BUILD_NUMBER.PadLeft(5, "0")
before_build:
- appveyor-retry dotnet restore -v Minimal
build_script:
- dotnet build "src\KScratch.Entity" -c %CONFIGURATION% -r %PLATFORM%  --no-dependencies --version-suffix %LABEL%
- dotnet build "src\KScratch.Contract" -c %CONFIGURATION% -r %PLATFORM% --no-dependencies --version-suffix %LABEL%
- dotnet build "src\KScratch.Portable" -c %CONFIGURATION%  -r %PLATFORM% --no-dependencies --version-suffix %LABEL%
- dotnet build "src\KScratchLog" -c %CONFIGURATION% -r %PLATFORM% --no-dependencies --version-suffix %LABEL%
after_build:
- dotnet publish "src\KScratchLog" -c %CONFIGURATION% -r %PLATFORM% --no-build --version-suffix %LABEL% -o artifacts\%PLATFORM%
- 7z a zip\KScratchLog_%PLATFORM%.zip %APPVEYOR_BUILD_FOLDER%\artifacts\%PLATFORM%\*.*
#test_script:
#- dotnet test "src\KScratch.Tests" -c %CONFIGURATION%
artifacts:
- path: zip\**\*.*
cache:
- '%USERPROFILE%\.nuget\packages'
on_finish: # Run the demo to show that it works

Experimenting with the Kudu API

1 -> Experimenting with the Kudu API

2 -> Building and Packaging .NET Core with AppVeyor

3 -> Parsing command line arguments in .NET Core

I’ve been playing around with the idea of some remote tools for Azure Functions using the Kudu API, mostly to make a nice way to edit and run Azure Functions from a local machine (large screen, easier access etc).

The repo is here https://github.com/jakkaj/k-scratch. It’s a work in progress.

I figure the parts I need are:

  • Log in from PublishSettings.xml
  • LogStream
  • Ability to query the functions in the site
  • Ability to list / download files
  • Ability to upload files

I decided to build the libraries on top of .NET Core.

I thought initially about a UWP app -> click + to add a new publish settings which will add a vertical tab down the left hand side. Each tab would be a little window in to that function. The LogStream, the files, editing + save would immediately upload and run it.

Perhaps I’ll get to that, but for now I’m building each bit as a standalone console app (.NET Core based) that takes the PublishSettings.xml as param.

So far I have the LogStream working, which was actually pretty easy!

You can grab a PublishSettings.xml file from your function by going to Function app settings / Go to App Service Settings / Click “…” and click Get Publish Profile.

You load the PublishSettings XML in to a nice entity. I created an entity to load the XML in to by using Xml2Csharp.com. Result entity here.

See this file for how the XML is loaded in to the entity.

The PublishSettings.xml file contains the Kudu API end points, and also the user and password needed to authenticate. Authentication is done using the basic authentication header.

Convert.ToBase64String(
                Encoding.UTF8.GetBytes($"{settings.UserName}:{settings.Password}"));

Once I had that organised, I could start calling services.

I tried a few ->

  • GET /api/zip/site/{folder} will zip up that folder and send it back
  • GET /api/vfs/site/{folder}/ will list a path
  • GET /api/vfs/site/{folder/filename will return that file

etc.

Great, I can get files! Change the HTTP method to PUT and I can upload files.

I then tried some LogStream. Using the new Bash shell in Windows, i was able to straight up Curl the log stream.

 curl -u username https://xxx.scm.azurewebsites.net/logstream

Straight away logs are streaming. Too easy! Next step was to see if the .NET Core HttpClient can stream those logs too.

 _currentStream = await response.Content.ReadAsStreamAsync();

Works really well it turns out – just read the stream as lines come in and you have yourself log ouput.

using (var reader = new StreamReader(_currentStream))
                    {
                        while (!reader.EndOfStream && _currentStream != null)
    {
         //We are ready to read the stream
         var currentLine = reader.ReadLine()

Full implementation of that file here.

Then I added a simple app – KScratchLog which takes the PublishSettings.xml path as the parameter and will start showing logs.

So why not just use curl? Simplicity of loading the PublishSettings.xml to get user/pass/API endpoint really.

Next steps – file download, change monitoring and uploading after edit. The goal is to allow editing in Visual Studio Code and have it auto save back to the App Service on file save.