Use NuGet Feed in Azure DevOps Artifacts in DevOps Build Pipeline

As part of our migration to Azure DevOps, we needed to consume a private NuGet feed in our ASP.NET application. Now as we had set up our private NuGet feed using Azure DevOps Artifacts previously, we just needed to get Azure Pipelines to use it.

To do so, I tried to follow articles on docs.microsoft.com to no avail, but eventually came across Travis Illig’s post. I attempted to use Option 1 as the default Azure Pipelines yml file contained a separate restore step.

So the changes I ended up making to the repository are as follows:

1.Added a NuGet.config file with the following content:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <solution>
    <add key="disableSourceControlIntegration" value="true" />
  </solution>
  <packageSources>
    <clear />
    <add key="NuGet Official" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="[Name of Feed]" value="https://[organisationName].pkgs.visualstudio.com/_packaging/[FeedName]/nuget/v3/index.json" protocolVersion="3" />
  </packageSources>
</configuration>

Note that we never had a NuGet.config file previously as these particular projects were never configured to run on a build server (yes, terribly bad practice). Also note that Azure DevOps Pipelines doesn’t seem to care what the “Name of Feed” value is.

2. Updated the NuGetCommand@2 task in azure-pipeline.yml file by pointing it to our NuGet.config file:

And that should be it. If you look at the console log of the subsequent build you’ll notice that Azure Pipelines is automatically setting up the credential provider for our private feed based on the feed url.

NuGet Packages from Azure DevOps Repository to Azure DevOps Artifacts

As part of our move to Azure DevOps (from BitBucket and our own hosted Jenkins), we needed to host some internally used NuGet packages (packaged up third-party commercial libraries).

To do so, we created a new Project in Azure DevOps. As this project is going to be used for all our common libraries, we’ll also host the NuGet feed under Artifacts of this project as well. Note: you need to you have Artifacts extension enabled in Azure DevOps.

To create the Feed, click on Artifacts, then select New Feed. You’ll be asked for details of the new Feed. Note that the Name is important for later on:

Now that we’ve created the Feed, for each distinct library, we’ll also create a new repository under that project – see end of this post.

And for each repository, we created a new azure-pipelines.yml file like so:

trigger:
- master

pool:
  vmImage: 'VS2017-Win2016'

steps:
- task: NuGetCommand@2
  displayName: 'Build Packages'
  inputs:
   command: pack
   packagesToPack: 'src/*.nuspec'

- task: NuGetCommand@2
  displayName: 'Publish Packages'
  inputs:
   command: push
   publishVstsFeed: '[FEEDNAME]'

Some notes on the above:

  1. The NuGet packages are defined using nuspec files, hence the packagesToPack using src/*.nuspec.
  2. [FEEDNAME] needs to be replaced with the feed name for the NuGet feed we created at the start.
  3. We are not defining the version the generated NuGet packages. For our packages, the version is manually defined in the nuspec file.

Now all you should need to do is commit a change to a repository, and watch Azure DevOps build then publish your NuGet packages.

Appendix A – Create a New Repository Under Azure DevOps Project

To do so, go into Repos. In the breadcrumb at the top of the page, click on the dropdown link, then select “New repository”:

From now on, you can use the same dropdown to to switch the repositories.

Running a Build Pipeline for ASP.NET with NUnit on Azure DevOps

We’re in the process of migrating a long-term project from our in-house build environment (Jenkins on Windows) to Azure DevOps. This is the first in a series of posts documenting our process.

This post is all about setting up the automated build process. Firstly, some particulars of our project:

  1. Project is in the DevOps git repository. It was moved from bitbucket.
  2. Solution contains three unit test projects, an ASP.NET application, console application, several assembly projects, all targeting .NET v4.7.
  3. Code is found under src/
  4. Unit Tests are using NUnit. This is important to know for later on in this post.
  5. Our Project tasks are currently controlled by rake tasks developed over the years (e.g. build, run unit tests, run selenium tests, create release artifacts). These will change depending on what Azure DevOps supports. Ideally we’d like to use as much of standard Azure DevOps tasks as possible.

Setting up Build Pipeline

I’m assuming you’ve created a project in Azure DevOps. Let’s get started by creating a Pipline file.

  1. In the Project area at https://{organisation}.visualstudio.com/{projectname}, click on “Pipelines”.
  2. Then select “New pipeline”.
  3. Now, select where you code is being retrieved from. We’re using “Azure Repos Git”.
  4. Now, select which repository in Azure DevOps (You may have multiple repositories in your Azure DevOps project).
  5. Configure your pipeline now. For this project we’re selecting “ASP.NET”.
  6. We’re presented with our azure-pipelines.yml file editor. This file includes tasks to build the project and run all tests in the solution.
  7. As we only have one solution for this project, I’m going to edit the “solution” property in the global variables to ‘src/TestProject.sln’ from ‘**/*.sln’. I like to be explicit here as sometimes we have different solutions for the same project. e.g. We might have a solution just to develop on the back-end in Visual Studio.
  8. Now select “Save and run”. Azure will prompt you whether you want to commit to master or commit to a new branch. I’ll select commit to master.
  9. Once Saved and committed, your build should now run.
  10. And now we wait for Azure to run the pipeline….
  11. And we’re done! However we have an issue with the VSTest task.

Fixing VSTest Task

  1. In VSTest task, we get a warning stating:
    ##[warning]Invalid results file. Make sure the result format of the file 'd:\a\1\s\TestResults\VssAdministrator_fv-az150_2019-04-02_11_26_15.trx' matches 'VSTest' test results format.
    Additionally in the console output of the VSTest task, it indicates that it couldn’t find any tests.
  2. After digging around, it turns out you need to have the nuget package “NUnit3TestAdapter” installed in your tests project. This allows the vstest.console app to find the tests in your tests project. We had never come across that previously as our Visual Studio installs always had the NUnit 3 Test Adapter extension installed and we had always controlled our automated tests via rake tasks using NUnit Console runner.
  3. After installing that, and committing the changes, we get all green!

So after all that, we now have the following:

  • Continuous building of our project
  • Continuous running of unit tests

What we need to do in the future is:

  • Deploy our project to a Windows Server
  • Run our end-to-end tests
  • Run integration tests
  • Generate a release artifact for a UAT and Production environment.

Roslyn Scripting

We recently needed to support local functions in runtime C# code. This runtime code is to allow us or the Customer to customise how a HTTP POST JSON document is constructed. At the time we were using CSScript to add runtime scripting to the application, however the default Evaluator was Mono which did not support local functions.

Fortunately Roslyn did. Due to that and some other requirements, we decided that we’d step away from CSScript and try and use Roslyn Scripting directly.

So here is the core of the code:

using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;

// ...

public static async Task<object> GenerateAsync(string codeAsString, GlobalData data)
{
    var options = ScriptOptions.Default
        .AddReferences("System", "System.Collections.Generic")
        .AddImports("System", "System.Collections.Generic");

    var script = CSharpScript.Create(codeAsString, options: options, globalsType: typeof(GlobalData));

    var state = await script.RunAsync(data);

    return (state.Exception == null) ? state.ReturnValue : throw new Exception("Runtime code had issues.", state.Exception);
}

Some comments on the code:

  • GlobalData type is the class that contains the variables that you want to expose to the runtime code. It needs to marked as public class. All its public properties are exposed to the script as global variables.
  • AddReferences adds namespaces/assemblies to the runtime code.
  • AddImports is effectively adding “using …” to the runtime code.

You can find a complete sample at roslyn-scripting-demo on GitHub.

Build ASP.NET Core with Jenkins on Windows

A post on how I configured Jenkins v2 on Windows for ASP.NET Core applications using Pipeline as code.

Before we start

  • Why Windows when ASP.NET Core can build and run on linux? This Jenkins instance was going to be used for other specific Windows builds as well. At least one of the ASP.NET Core applications needs to be built against the .NET Full Framework.
  • Why Jenkins? It’s what I’ve been using personally or on other teams for many years now. I’m sure Teamcity or VSTS are more than capable.
  • I use rake to run my build tasks (choco install ruby)
  • I’m using git (choco install git)

Versions as of writing

  • Windows 10 Pro (Build 15063.138)
  • Jenkins v2.55.
  • git 2.12

Install Jenkins

I’m using Jenkins v2 with the new Blue Ocean UI (currently installed as a plugin).

  1. Go to https://jenkins.io/download/
  2. Download either LTS or Weekly installer for Windows.
  3. Run the installer. I usually install Jenkins to an empty volume (e.g. D:\).
  4. Go into Manage Jenkins -> Manage Plugins. Install “Blue Ocean”. Restart Jenkins when finished.

Install VSTools

This installs MSBuild and related files. I’ve based it on this answer on StackOverflow.

  1. Go to https://www.visualstudio.com/downloads/.
  2. Scroll down to the expandable section and click on “Other Tools and Frameworks”.
  3. Select “Download” button for “Build Tools for Visual Studio 2017”.
  4. Open up Command Prompt and execute the following: vs_buildtools.exe --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Workload.WebBuildTools --quiet

You can find more information about those component identifiers at https://<docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools>

A couple of notes about MSBuild and Visual Studio 2017:

  • MSBuild has now been moved into the Visual Studio 2017 installation folder.
  • You can install Visual Studio 2017 anywhere.
  • Visual Studio 2017 now supports side-by-side installation between the different sku’s (enterprise, professional community, buildtools).
  • There is no standard registry key or environment variable that indicates where Visual Studio, let alone MSBuild is installed.
  • Microsoft has some recommendations on how to find where Visual Studio 2017 is installed at. E.g. vswhere.
  • It is no longer as easy to determine where MSBuild is, unlike before.

To get around this, what I’ve done for my environments is add an MSBUILD15 environment variable that points to the folder of msbuild. Any build scripts I have bomb out with a helpful message if that variable isn’t set.

Note that you can add this variable through Jenkins so its presented to your build scripts without having to edit Windows settings. Go to Manage Jenkins -> Manage Nodes then edit the node that you are configuring.

Configure Your Project for Pipelines

As we will be using Pipelines in Jenkins (instructions to Jenskins on what to do with your project), we need to create a Jenkinsfile in the root of our repository. This will tell Jenkins what the steps are for our pipeline and how to execute them.

As this is a simple project and I’m using rake to execute the task, this is what my Jenkinsfile looks like:

node {
    stage 'Checkout'
        checkout scm

    stage 'Build'
        bat 'rake build'

    stage 'Test'
        bat 'rake test'
}

You can read all about Pipelines at https://jenkins.io/doc/book/pipeline/.

Create new Pipeline

As I stated before I’m using Blue Ocean so the steps below reflect that.

  1. In the normal Jenkins view, click on the “Open Blue Ocean” button in the nav-bar.
  2. Select “New Pipeline”.
  3. Select where your code is stored. For me this is “Git” (this project is on Bitbucket).
  4. Enter in the repository URL and create a new Credential for it. I use SSH Private Key which is configured as a read-only key for this particular repository in bitbucket.
  5. Select Create Pipeline.
  6. Jenkins should connect to the repository, find the Jenkinsfile and perform the defined tasks. If everything was run successfully, you should see something like this:

Poll Repository for Changes

As my Jenkins instance is running within a LAN and is not visible to bitbucket, we need to tell Jenkins to poll regularly for changes to the repository. To do that:

  1. Edit the project in Jenkins (Select the cog in the top-right hand corner).
  2. Scroll down to “Scan Multibranch Pipeline Triggers” and check the checkbox and select an appropriate Interval:
  3. Save

And that should be it.

Unable to start kestrel – An attempt was made to load a program with an incorrect format

Hopefully this saves someone some time in the future.

I was developing a throw away ASP.NET Core app on .NET Full framework in Visual Studio 2017. I noticed that the Platform target was set to x86 (the default), so I changed it to AnyCPU then redeployed.

I tried to run it from the console (I love how I can just run a webapp from the console now… so awesome), but got the following error:

crit: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to start Kestrel.
System.AggregateException: One or more errors occurred. ---> System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

Turns out that even though I had changed the Platform target via the Project Properties, there was a setting within the csproj that indicated an x86 runtime.

To solve the issue, open up the csproj file for your project and change the x86 part of the value of the RuntimeIdentifier element to x64.

So instead of (for example):

<RuntimeIdentifier>win7-x86</RuntimeIdentifier>

You want:

<RuntimeIdentifier>win7-x64</RuntimeIdentifier>

Save that and rebuild or redeploy your project.

For more information about the above, I first found the error message described at:

https://docs.microsoft.com/en-us/aspnet/core/publishing/iis#platform-conflicts-with-rid.

Information about the RuntimeIdentifer property, see https://docs.microsoft.com/en-us/dotnet/articles/core/tools/csproj#runtimeidentifier. For information about the RID values, see https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog.

REPL Development using F# Interactive in Visual Studio Code

Now that we have Ionide installed, we can do REPL development by using the F# Interactive console (FSI).

There are a couple of ways of getting FSI to run your code:

  1. Sending the selected code to FSI.
  2. Sending the current line to FSI.
  3. Sending the whole file to FSI.

For the first two options, you don’t need to be working in an existing F# file. You can just create a new tab, start typing, select the code and send to FSI.

Caveat: I found that if you wanted Intellisense to work you needed to be working in a saved .fsx or .fs file (see reported issue). You can’t just change the language mode to F#.

Start FSI

To get started with FSI, you need to start it. To do so, open the Command Palette (⇧⌘P) and typing in “FSI: Start”.

The output panel will display like so:

Run code in FSI

Type in some F#. Then select the F# code you want to run and then select “FSI: Send Selection” from the Command Palette or type in ⌥Enter. This will take the code you have selected and run it in FSI and give you the result in the Output panel.

If you made a mistake in your F# code, you’ll see the compiler or runtime output in the Output panel. E.g.:

You can also send the whole file to FSI, however for that you need to be working in an existing file. Once you are working in an F# file, you can send the whole file (including your current unsaved changes) by selecting “FSI: Send File” from the Command Palette. However I found it easier to just select the content of the file (⌘A) and then send the selection to FSI.

Getting started with F# in Visual Studio Code on macOS

Previously I showed how to install F# on OSX. In this post I’ll start showing you how you can start devloping F# in Visual Studio Code on OSX (macOS… whatever).

Assumptions

  • You are using OSX. These instructions may work on Windows, but I haven’t tested on Windows. Let me know if they do.
  • You have mono already installed. If not, follow the instructions.
  • You have Visual Studio Code (VSCode from now on) installed. If not, download it and install it.

Before we Get Started

These instructions were taken when using mono 4.4.2, VSCode 1.4, OSX 10.11.6, and Ionide extension v2.2.7. If any of the below does not work for you it may be due to differences in the versions of any of the above.

Installing Ionide Extension

The bulk of the F# support comes from the excellent Ionide project which I believe was originally developed for the Atom editor. There are a set of extensions for VS Code.

So as with all other extensions in VSCode, open up the Extensions view via one of these methods:

  • click on Extensions icon in View Bar, or
  • press ⇧⌘X, or
  • Open up the Command Palette (⇧⌘P) and type in Install Extensions and press enter.

Now search for Ionide. You should see at least the three extensions below:

Install each extension (click on the green install button) then restart VSCode (rather than having to enable each extension). I installed them in the following order, though I’m assuming the order doesn’t matter: ionide-fsharp, ionide-fake, ionide-paket.

Now that Ionide is installed, you have should everything needed to get into F# now. There are a couple of ways you can do that:

I’ll describe each in the next set of posts.

C# and F# Xamarin iOS Quick Start Projects

I’m starting to get into iOS development using Xamarin.

So to start out, I followed the Quick Start tutorials for Xamarin Forms but as a twist decided to also do it using F#. I didn’t just figure out how to do it in F# however, I used the following resources to help out:

You can find my implementations of the Quick Start on github at:

Xamarin Forms Quick Start in C# and F# on GitHub

Though I want to draw attention to one part of the project which was a puzzle for me given my current knowledge (or lack thereof) of F#.

Async Event Handlers in F#

In the Quick Start tutorial the Call button click is an async event handler. So this (taken from MainPage.xaml.cs):

async void OnCall(object sender, EventArgs e)
{
        if (await DisplayAlert(
                        "Dial a Number",
                        "Would you like to call " + translatedNumber + "?",
                        "Yes",
                        "No"))
        {
                var dialer = DependencyService.Get<IDialer>();
                if (dialer != null)
                        dialer.Dial(translatedNumber);
        }
}

So its an async event handler in C#, but how on earth do you do this in F#?

As F# has similar but different ways of doing async (that came before C# async) we need to code it differently. So here is the equivalent in F# (taken from MainPage.fs). Note that I’ve split it into two methods to make a bit clearer:

member this.makePhoneCall = async {
        let! ok = Async.AwaitTask(this.DisplayAlert("Dial a Number", sprintf "Would you like to call %s ?" translatedNumber, "Yes", "No"))
        if ok then
            let dialer = DependencyService.Get<IDialer>()
            if not(Object.ReferenceEquals(dialer, null))
            then dialer.Dial(translatedNumber) |> ignore
    }

member this.OnCall(sender : Object, e : EventArgs) =
    this.makePhoneCall |> Async.StartImmediate

One of the key differences between C# and F# async is that in F# the async block (async { ... } in makePhoneCall) is a specification; it does not execute the code. You need to specifically start it using Async.StartImmediate in OnCall. This method starts the async block immediately on the current thread which in this case is the UI thread (which is needed as we’re interacting with the UI).

Some resources I found really helpful:

Install F# on OS X

As the title indicates, this is how to install the various bits and pieces to be able to compile F# applications and run F# scripts on OS X.

There are two ways I ended up doing it, both involve installing Mono. I went with the first option initially until I ended up doing iOS development using Xamarin.

Option 1 – Install using Homebrew

Assumptions

You have homebrew already installed.

Install mono

Pretty straight forward:

  1. Open Terminal
  2. Install mono and nuget via homebrew: brew install mono nuget

And away you go.

Option 2 – Install Xamarin Studio

  1. Download Xamarin Studio.
  2. Run the installer and choose the options that suite you and then follow the prompts. I actually went with a ‘manual’ install of Xamarin Studio as I didn’t want or need Android development resources installed on the Mac I was using.

How to manually install Xamarin Studio components

I went with this option as even though I didn’t want to install Android, Xamarin Studio was still going to install Java and Android SDK.

So this is how I performed a manual install:

  1. Run the Xamarin Studio installer.
  2. Accept the terms and select Continue.
  3. Select the products to install then select Continue. I chose Xamarin.iOS. Note: This won’t actually start the installation.
  4. On the “Please configure the installation” page, Select the “Xamarin Installer” in the menu bar, and then choose “View manual install instructions”. This will then show a new dialog with instructions on how to install the various bits of Xamarin Studio. It basically boils down to downloading a couple of seperate installers (Mono SDK, Xamarin Studio, Xamarin iOS product) and installing them. Note that if you wish to you can completely ignore the Java and Android.SDK options as I did.

Regardless of how you installed Xamarin Studio, you should have the various mono executables in your Terminal path.

Lastly, you can apparently use homebrew mono and Xamarin together though for me atm, it was just easier to stick with what Xamarin installed.