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.

    90B715C5-82A6-4ACC-BD13-955FE7AFA6D1

  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:

    6224A3E5-0567-432B-853D-9F3764ED4ADC

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:

    9ACE8065-F665-4335-AAFF-7D287DA40B90

  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.

Setting up TortoiseSVN to connect to svn+ssh

I was tasked to help a customer move their subversion server to the “cloud” (azure in this instance).

Due to various factors, we chose not to use a VPN but rather go with svn+ssh to connect to the remote subversion repository.

Anyway, this post is to describe how to configure TortoiseSVN to connect to the svn+ssh remote server.

Firstly, the software I used:

Assumptions

  • I’m assuming you are using a keypair to authenticate with the svn+ssh service.
  • I’m also assuming that you have created a keypair that Putty can use. Follow the instructions at https://the.earth.li/~sgtatham/putty/0.67/htmldoc/Chapter8.html#pubkey-puttygen. If your keypair was generated using openssh, then you’ll need to convert it to a format that Putty can use. Puttygen can be used to do that, although it doesn’t support the newer format from openssh.
  • Lastly, I’m assuming your keypair uses a passphrase. If not, you definitely should be.

Configure Putty

We need to configure a new Saved Session in Putty that we will refer to later in TortoiseSVN. This will tell TortoiseSVN the connection details and private key to use when connecting to the svn+ssh service.

  1. Launch Putty.exe. If you used the msi installer, it should be on your desktop. You’ll the standard Putty dialog show:

    B2B2ACB4-FCEE-484F-9912-111C7F6E2D3F

  2. We need to tell Putty where to find our Private Key on disk. So in the left-hand panel drill down to Connection->SSH->Auth and you’ll see this:

    E655FCE2-5CF9-426C-A56B-D9D82BCD7AD1

  3. Enter in the path to your Private Key:

    B9CDF088-2160-4BB4-A36D-D3346BA6525B

  4. Now we need to tell Putty our Host connection details. So (1) go to the Session option. (2) enter in your Host and Port connection details; (3) Enter in a and in the text box below “Saved Sessions” label, (2) enter in a descriptive label then (3) click “Save” button. You’ll see that label show up in the list box below the text box. This has saved the details you entered into a named config so we can refer to it in TortoiseSVN.

    8AF062C9-7C21-4AD1-8A21-A505A91D1D88

  5. Finally, we must save these details as a Saved Session. In the text box below “Saved Sessions”, (1) enter in a descriptive label. I strongly recommend not using any spaces. It makes a big difference later on.

    Now (2) click on the “Save” button to save the details as that label.

    FB10F1E3-94A9-4258-8F2F-7C1964A4D5E2

  6. You can close Putty now (click the Cancel button).

Configure TortoiseSVN

We need to quickly configure TortoiseSVN to know how to connect to an svn+ssh connection.

  1. Open up your TortoiseSVN settings dialogs (you can find it in your Programs menu or by right-clicking in Windows Explorer and selecting TortoiseSVN -> Settings).

  2. Navigate to Network in the left-hand panel. In the “SSH client:” text box enter in the path to the TortoisePlink.exe utility. If you installed TortoiseSVN with the defaults, the path should be C:\Program Files\TortoiseSVN\bin\TortoisePlink.exe:

    EE131FB3-9124-4579-903C-D0EDA23FF7DB

  3. Click OK.

Test the Connection

We can now attempt to connect to the remote subversion repository.

Open up the TortoiseSVN Repository Explorer and type in the url to the remote Subversion repository. The svns+ssh url is as follows:

svn+ssh://(username)@(putty_session_name)/(repository_name)/

Where:

  • username : The name given to you by the Subversion administator.
  • putty_session_name : The name we used in the Save Sessions text box in Step 4 in section “Configure Putty”. E.g. “examplesvn”
  • repostitory_name : The name of the repository you’re connecting to.

So for example, if Bob wanted to connect to the research repository, the url would be:

svn+ssh://bob.smith@examplesvn/research/

Note: If this is the first time you are attempting to connect to the remote Subversion repository, you will prompted on whether you trust the server you are connecting to and want to cache the server’s key.

BEBFD399-935E-43D4-BEBC-BB5D59D6B027

You will then be prompted for your Private Key passphrase:

D8A5352D-8AD4-44B0-A2F7-91EE582B87B1

And then re-prompt several more times. After which if everything was correct you’ll see your repository in the Repository Browser.

The reason why were you prompted several times for your passphrase is due to how svn protocol works whereby it makes multiple seperate connections to the server. And each connection requires a re-authentication. This will get very annoying after a short time.

To reduce the pain, we’ll use a utility called Pageant that will cache your decoded Private Key in memory after the first time you enter in your passphrase.

Setting up Pageant

The way Pageant works is that the first time it runs, it prompts you for your Private Key passphrase and then whenever Putty needs to use that Private Key, it uses the already decoded Private Key information to do the ssh handshake.

The easiest way of doing this, is running Pageant on Windows startup.

  1. Open up the Task Scheduler (otherwise known as Scheduled Tasks).

  2. Create a Basic Task by clicking on the “Create Basic Task…” in the Actions panel:

  3. Enter in a name for the task then click “Next >”.

  4. Select “When I log on” option for when you want the task to start. Then click “Next >”.

  5. Select “Start a program” for the action. Then click “Next >”.

  6. For the “Program/script:” value, enter in c:\Program Files (x86)\PuTTY\pageant.exe assuming you used the MSI installer for Putty. You also need to add the path to your private key into the “Add arguments” text box. Make sure you surround the path in double-quotes (just in case the path has spaces). So something like this:

    E4E33C88-DD94-49A9-B187-F8A72301658B

  7. Click Next >.

  8. If you’re happy with what you entered in, Click “Finish”.

Now you definitely want to test this out, so log out of Windows then log back in. When you log in, you should see the following prompt from Pageant:

2160FF9C-3E95-4693-8F3F-5BE9D7B12133

If the passphrase is correct, the dialog will just disappear.

From now on, when you connect to the remote Subversion repository, you will no longer be prompted for any passphase.

Happy days!

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.

Setup SSH Keypair in Bitvise SSH Client

In case you use the bitvise SSH Client to connect to various ssh based services, here is how to set up a new SSH keypair.

Assumptions

  1. You are using Bitvise SSH Client 7.15. If you are using something different, the instructions may differ. See Bitvise for help then.
  2. You do not have an existing SSH keypair that you want to use.
  3. You know what public and private keys are (SSH keypair). See Understanding SSH Key Pairs

How to Create SSH Keypair

  1. Start Bitvise SSH Client.
  2. Under the Login tab, click on the Client Key Manager link:

  3. In the Client Key Manager dialog, select “Generate New” button:

  4. You should be able to keep the defaults, however definitely enter in a strong, unique passphrase. When done, press “Generate” button:

How to Export Public Key

Now that the SSH keypair is generated, we need to export the public key to give to the third-party/external service.

Note: I indicate to export as OpenSSH format this is the format that is used when configuring a linux remote machine for SSH/SFTP access and what github uses as well. Another online service might need it in SSH2 format so check.

  1. Again, in the Client Key Manager, highlight the ssh keypair you just generated, and select “Export” button.
  2. In the “Export Public or Private Key” dialog, select “Export public key” radio button then “OpenSSH format”. Then click “Export” button. Note that you’ll be prompted for a file location to save to.
  3. Find the file just created and depending on how the third-party requires it, either send the file or enter in the contents into the web-form, authorized_keys file, etc.

Finally I would also recommend exporting your Private key and keep it in a safe place in case you decide to use a different client or move computers, etc.