First, the background. I’ll explain the problem and the goal. Later I list all of the steps to build out the CI/CD process.


I recently started using the Ionic framework to develop cross-platform mobile apps. I like the idea of using HTML with Angular and TypeScript because we are already doing that for our web apps. (I’m not going into the pros and cons of a hybrid mobile app or any of that stuff, that is not what this blog post is about.) Anyway, along with Ionic, I evaluated Ionic Pro, a paid service that provides some pretty cool features for teams building Ionic Apps. For my non-mobile apps (Web Apps, etc.), I have testing environments named SysTest, QA, UAT, and of course, Production. Those multiple environments can be tricky to manage for mobile app development. Ionic Pro can help here and in particular, I like Ionic’s features: View App, Deploy, and Package. These tools make it pretty easy for us to test our mobile apps through all of those phases and then deploy it for production. Read up on the View App – it is pretty cool. However, I think their implementations, while a great start and very useful, fall pretty short of what I really need to create mobile apps in an enterprise development environment. But I knew I could get all of my tools to work together and it took some work but I’ve got a good model now that I wanted to share with the world.

There are a lot of possible ways to do this. I’m using TFS and Octopus Deploy and I am assuming that you, the reader, are familiar with those products already. If you use a different CI server or deployment system, I’m sure you can take the concepts from here and apply them to your environment.

My Current CI Pipeline for other (non-Ionic) apps

First, an overview of my DevOps pipeline for my other apps. I think this is a fairly straight forward/typical model.

  1. Developer makes a change locally.
  2. Developer builds locally to test application, including debugging, etc..
  3. Developer commits changes to source code repository (Git in TFS).
  4. Commit triggers a CI build:
    1. Gets code from source control
    2. Loads dependencies such as NuGet, NPM, etc..
    3. Compile
    4. Test
    5. Packages the application
    6. Publishes the Package to Octopus Deploy and create a release
  5. When triggered, Octopus Deploy updates configuration settings (variables, connection strings, etc.) for the specific environment and deploys the packaged application.
  6. Users can easily trigger step 5 for any of the environments (SysTest, QA, UAT, Prod, etc.). If you are new to this, remember that when Octopus deploys, it uses the same package for each environment. So we never go back to step 4.

Another note on the current process: I like to be able to trace my changes from checkin to build to deployment. One way I do that is to use the same value for the TFS Build Number, the Octopus Package version, the Octopus Release Number, and assembly version number.

I’ve simplified the process a bit for purposes of this post but here are some key takeaways:

  • After a developer commits the code, they don’t touch it again.
  • The code is compiled once on the server (not on a desktop machine by a developer which could introduce problems)
  • The same compiled application is deployed to each environment
  • The only changes are the configuration values managed by Octopus.
  • It works GREAT!

My goal was to get as close to this set up as possible. I think I did.

Unfortunately, Ionic Pro’s feature isn’t rich enough

Doesn’t Ionic Pro already allow you to move code through different environments? Sort of – but it is not good enough. What does Ionic Pro offer? With Ionic Pro, users can push the code to Ionic by committing and pushing changes to a Git repository hosted by Ionic. This is not meant to replace your normal Git repo. I think this is a pretty creative and easy way to push code to Ionic. Ionic will then build the project for me. Ionic supports multiple channels (sort of like environments). After code is committed to Ionic and then built by Ionic, the build can be automatically or manually deployed to a channel. With the Ionic View app on a mobile device, you can easily test versions from each channel. You can create any channels you like (we used SysTest, QA, UAT, and Prod) and Ionic Pro suggests testing the code in each area and then promoting the build to the next environment. The problem with this model is that if I “promote” the build from SysTest channel to QA channel, there is no way to change configuration variables. So while it seems cool, this is pretty much useless to me. Most likely any I am running or testing in SysTest, QA, UAT, or Prod will have different users, permissions, data, passwords, database connections, logging systems, etc. for each environment. After a bit more research I figured out that Ionic supports Git branches. Ok, now this is getting interesting and my brain starts trying to figure out how to make this work. In Ionic, each commit triggers a build. And the build can be deployed to a channel. So the next obvious idea (and one I think Ionic promotes) is that if developers need different settings for each environment, they should change the variables on their dev box and then push the changes to a new branch. The flow would look like this:

The Prescribed Ionic Pro Design(no good)

  • Dev makes a change.
  • Developer builds locally to test application, including debugging, etc..
  • Developer checks code into Git repo (not Ionic, I mean TFS, GitHub, whatever)
  • Dev checks in change with SysTest variables to the SysTest branch in Ionic.
  • Ionic builds and deploys to the SysTest channel.
  • After testing in SysTest, the developer would update the variables for QA locally and then commit the changes again, this time to the QA branch.
  • The developer must make sure to check in the correct code without any updates since the previous SysTest deployment.
  • (I assume the developer does not check these changes into the normal source control repo.)
  • Ionic builds and deploys to the QA channel.
  • Etc., etc.

My Design

While the previous model could work for some people, it is error prone and seriously flawed. There is too much manual intervention and too many chances for human error to occur. Each time a developer checks in the changed configuration values there is a risk that she or he will introduce a bug. So I came up with this better, more automated, harder to set up, but certainly safer and less error prone plan:

  • Developer makes a change locally.
  • Developer builds locally to test application, including debugging, etc..
  • Developer commits change to TFS Git repository.
  • Commit triggers a CI build:
    • Gets code from source
    • Loads dependencies such as NuGet, NPM, etc. This is done later by Ionic Pro
    • Compiles This is done later by Ionic Pro
    • Tests
    • Packages the application
    • Publishes the Package to Octopus Deploy and create a release
    • (note this isn’t really a “build” but it uses TFS’s build system.
  • When triggered, Octopus Deploy updates configuration (variables, connection strings, etc.) for the specific environment and “deploys” it. However, in this case, “deploy” means to take the code and commit it to the specific Ionic branch as needed.
  • Ionic then builds the branch and deploys the branch to the appropriate channel.
  • Octopus and Ionic repeat the process as needed for each: SysTest, QA, UAT, Prod (etc.)

Here is my same list of takeaways, with notes for the new design:


  • After a developer commits the code, they don’t touch it again. Yup
  • The code is compiled once on the server. Not exactly. It is compiled on the server but not once. It gets compiled for each environment
  • The same compiled application is deployed to each environment. Nope
  • The only changes are the configuration values managed by Octopus. Yup
  • It works GREAT! Yup!

My design also has some big flaws but I think the compromises are pretty good. For example, I’d like the code to be built once instead of built for each environment. But due to the nature of Ionic apps and Ionic Pro, we are stuck. The good part is that while we are doing multiple builds, they are all done by the same user/environment (Ionic Pro), from the same source code (it is packaged once), and it is all automated with no human interaction.Another weird thing is that my TFS build isn’t really building it and my Octopus Deploy isn’t really deploying a finished product (it just pushes code to a Git remote). But on the other hand, if you were to compare this process to my other projects, there is a lot of consistency. And I can still use the Octopus dashboard to see the status of my app in different environments.

How to set this up

This doesn’t sound too complicated but parts were a pain to figure out. Here are the steps to set up:


Of course, we need a Git repo. Do what you want, I put mine in our on premises installation of TFS. Pretty straightforward, I won’t provide instructions.

Source Code

Add the source code for your Ionic project to your Git repo. Again, I am not providing instructions on how to use git.

Link to Ionic Pro

Link your Ionic project to Ionic Pro (I assume you have an account already) with a command like: ionic Link –pro-id YOUR_ID


Next, we need our Build. Again, it doesn’t really build anything but it is the heart of the Continuous Integration pipeline. I use TFS but you can use what you want to accomplish the same thing. The build has 6 steps:


Here are the steps. Of course, you can choose to do this differently, especially the 4 Octopus Deploy related steps.

a. Get sources


b. Update Octopus Package Version

I have a variable that I use for setting the Octopus Package number and release number. It is based on my TFS Build Number but needs to be set with PowerShell.

c. Package

Yes, package is the next step. I don’t actually build anything. Ionic Pro is expecting the source code, not the compiled versions.


d. Push Package to Octopus


e. Create Octopus Release


f. Deploy the release


Octopus Tentacles

Configure the tentacles (3 on one machine, 1 on another)

To set up Octopus Deploy, you need an multiple environments (in my case SysTest, QA, UAT, and Production). Each environment needs a Tentacle. To simplify this, I use 2 servers and 4 tentacles. In this case, the servers/tentacles will be a temporary place where the code goes on its way to Ionic Pro. So I set up:

  • Server A
    • SysTest tentacle
    • QA Tentacle
    • UAT Tentacle
  • Server B
    • Production Tentacle

Note: I do this to save resources. You could easily use a different server for each tentacle. But the server does so little I decided to conserve resources. I do split dev and prod servers because eventually, the prod code may have values (passwords, etc.) that developers don’t have access to. Since developers don’t have access to “Server B”, it all works out.

Configure Octopus Deploy

My Octopus Deploy project is pretty straight forward. It has one step


There are a few interesting configurations to the step:

Use this setting to update variables in the package.json file.


Use this to transform the config.XML file


I find that Ionic apps aren’t as configurable as I would like. I want lots of values to be configurable. The problem is that I can’t just put a variable placeholder in config.xml. If I did, the XML would not be valid. Consider this snippet of XML from my config file. Note that the #{XXX} syntax represents Octopus Deploy’s variable replacement token syntax. But Octopus only updates my variables during deployments. How can I run this locally?

<plugin name="cordova-plugin-ionic" spec="^4.1.6">
<variable name="APP_ID" value="abcdef" />
<variable name="CHANNEL_NAME" value="#{ChannelName}" />
<variable name="UPDATE_METHOD" value="none" />
<variable name="WARN_DEBUG" value="true" />
<variable name="UPDATE_API" value="" />
<variable name="MAX_STORE" value="2" />

The answer is config transformations. I created a second file named config.release.xml. I put the variable tokens inside this new file. As long as I tell Octopus to update variables in my config.release.xml file and also tell it to run config transformations, the values will eventually find their way to my config.xml file after a deployment. This is using the same features used by ASP.NET for web.config transformations. You can read more here.

	<?xml version='1.0' encoding='utf-8'?>
	<widget id="com.YOURDOMAIN.YOURAPP" version="1.0.2" xmlns="" xmlns:cdv="" xmlns:xdt="">
		<plugin name="cordova-plugin-ionic" spec="^4.1.6">
			<variable name="CHANNEL_NAME" value="#{cordova:plugins:cordova-plugin-ionic:CHANNEL_NAME}" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
			<variable name="UPDATE_METHOD" value="#{cordova:plugins:cordova-plugin-ionic:UPDATE_METHOD}" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>

Use this to update variables in other files


Here are the list of Variables:

CHANNEL_NAME and UPDATE_METHOD are used to update the values for Ionic Pro Live Deploy


OK, so at this point, we are set up for our Ionic project to get checked in to source control, automatically packaged up by TFS and then deployed by Octopus. But how do we get it to Ionic Pro? We’ve got a bit more work to do and it involves some more set up on our target servers. Earlier I mentioned 2 target servers called (for this sample) Server A (has SysTest, QA, and UAT tentacles) and Server B (has the prod tentacle). I’ll focus on Server A for now but you can set up Server B the same way.

Security for Ionic Pro with SSH

Since we’ll be using git to push changes to Ionic over SSH, we need an SSH Key. Getting this setup was a little tricky, especially since I don’t have much experience with SSH.

  • First I created a new account in Ionic. I want it to be clear that my code changes are checked in by my CI system, not me. Our account is named DevOps.
  • Create an SSH Key
  • Here’s a trick. Octopus Deploy runs as the System Account. But when you generate the SSH key it will go to a folder for you, the logged in user. Since I was using Git Bash to generate my SSH key, I ran Git Bash as “System Account” with a PSExec command like this:
    • psexec: psexec -s -I gitbash.exe

By doing this, my SSH key will be saved in the correct place.

  • Upload the SSH Key to Ionic for the new user account. In Ionic, go to Account Settings > SSH Keys
  • On the tentacle server you also need to configure the user account that you used to connect to Ionic (the devops account)
    • git config “devops@…”
    • git config “devops”

Server Setup for Git Repos

Remember that on each tentacle, all we are really doing is getting the changed source code from Git and then checking it in to Ionic.

  • On each server, install GIT and install NPM
  • Next, I created a folder C:\IonicStaging. Inside that, a folder per environment:
    • C:\IonicStaging\SysTest
    • C:\IonicStaging\QA
    • Etc.
  • For each folder above, we need to set it up as a git repository by:
    • Navigate to the folder such as C:\IonicStaging\SysTest
    • Execute the GIT clone command for your code. You can clone from your regular Git repo or you can clone directly from your Ionic Pro source as well.
    • Create a local branch for each folder:
      • Example, in the SysTest folder: git checkout -b SysTest
    • Create an Ionic Remote for Git:
      • git remote add ionic ssh://
    • Test it out by pushing changes from your local branch to a SysTest branch (it will create it for you) on the remote: Ionic
      • git push ionic SysTest

Setup Channels on Ionic Pro

You will need a channel for each environment

  • Create a channel for each such as SysTest, QA, UAT (Production is there by default)
  • Set the auto-deploy for the channel as such:



All this setup is great but it won’t work without a little PowerShell love. Octopus is pre-configured to run PowerShell scripts during the deployment, if they exist with the correct name. So I have a script named deploy.ps1 inside of my Ionic app. It looks like this:

In the script above, the “#{xxx}” format represents variables that Octopus will replace. You will recall that earlier when I configured Octopus Deploy, I set it to update variables in the file named deploy.ps1.

	$sourceRoot = $pwd
	$env = "#{EnvironmentName}"
	$destinationRoot = "C:\IonicStaging\$($env)\MyMobileApp" 

	$exclude = @('[Content_Types].xml','*.nuspec', '.git', '_rels', 'package', 'deploy.ps1')
	#clean out the target
	Remove-Item $destinationRoot -recurse -Exclude $exclude
	#copy files to target
	Get-ChildItem -Path $sourceRoot |ForEach-Object {
	Copy-Item $_.fullname "$destinationRoot" -Recurse -Force -Exclude $exclude
	Set-Location -Path $destinationRoot
	$gitPull = "git pull ionic $($env)"
	Invoke-Expression $gitPull
	#this will set the npm version in package.json (Octopus.Release.Number will be updated first)
	npm --no-git-tag-version version #{Octopus.Release.Number} --allow-same-version
	#this will set the ionic version based on the npm version
	git add -A
	git commit -m "#{Octopus.Release.Number}"
	$gitPush = "git push ionic $($env)"
	Invoke-Expression $gitPush

The script does two main things:

First, it updates the version number in package.json using “npm –no-git-tag-version version #{Octopus.Release.Number} –allow-same-version” and you will note that I am setting the version to the Octopus Release Number. It also calls “ionic-version” which copies the package.json version number into config.xml.

The other main function of this script is to get the files into Ionic Pro. The script copies the source files that have been deployed with Octopus (remember, they have not yet been compiled) over to the IonicStaging folder that we created on the tentacle server. Then it does “git add”, “git commit” (using the Octopus Release Number for the comment), and “git push” to Ionic.

Consistent Numbering

Did you notice along the way that I use the same number for my TFS Build Number, Octopus Release Number and Ionic App Version Number (and assembly version number for my .NET apps)? That gives me a great way to trace problems from source code to installed application and back!

Finally Done!

Although each little step is pretty simple, it is fairly complicated to get the whole thing working. To me, it is totally worth it. I love having a pipeline that “just works”:

Check in code –> Code is deployed!

At this point, I’m just hoping I didn’t miss any steps when I wrote this.


OK, I’m a little late at getting to this but I have just posted the code for my recent talk: Creating Awesome Chat Bots with the Bot Framework and C#.

To all that attended, thanks for joining me. I had a lot of fun preparing and presenting.

The code is here:

Unfortunately, this isn’t the easiest sample to get running. I think the code serves as a good example of some great things you can do with bots. However, if you want to actually use it, there are several steps that need to be done in advance. I’ve copied the text below from the readme file. As I say in a lot of my presentations, each step is pretty easy. However, putting them all together, especially for the first time, can be tricky. There are lots of good articles and videos on the web already for getting started with Bot Framework (and LUIS and QnA). I suggest reading up a bit and then follow my very basic instructions to get the code sample running.

Contact me if you have any questions or issues. Have Fun!

Getting Started

Before using this code you need to get set up

  1. Follow the instructions in the Prerequisites section here:
  2. Install the emulator. The link is on the same page as above in the section: “Test your bot”

  3. You will also need:

Resources Setup

  1. After you create a LUIS account, create a LUIS app. You can leave it blank if you want. TechBashBot.sln contains a file LuisModel.json that can be imported to get started quickly.

  2. After you create a QnA Maker account, create a QnA service. You can import the questionsn and answers from TechBashBot.sln using the QnAMaker.tsv file.
  3. After you create your Azure Account, create a Web App Bot. Just add a resource and search “bot”, then choose Web App Bot

App Configuration

Once all of your resources are set up, you need to configure the code:

  1. Update the web.config file with the MicrosoftAppId and MicrosoftAppPassword for your new Web App Bot

  2. Update LuisDialog.cs by setting the new LUIS model id and subscription key
  3. Update QnADialog.cs by setting the QnA Service subscription key and knowledgebase id

If you spend your day in a code editor like Visual Studio, you want to make the experience as good as it gets. One simple change you can make is to change your font. You’ll be surprised how a font change can make your code more readable and make writing software more enjoyable.

Here is an example of code using the font Consolas


This next sample uses FiraCode. In many ways it looks similar to Consolas, but it adds some cool features. In particular, it works really well with symbols that are made up of multiple characters. Check out the Lambda expression in the sample below. It makes “=>” look really cool. It works really well for “==” and “===” and “>=”, etc. These things are called Ligatures. I really don’t know much about fonts. It is all explained pretty well on GitHub where you can download and install the font (they provide instructions too).



Here is a screenshot from the GitHub site for FiraCode that shows how it looks for various multi-character symbols…


So, chose a font that works great for you! I like FiraCode. You can read more and download FiraCode here.




I’ve been using the Azure Portal more and more these days and one thing is for sure, I still have a lot to learn. There is soooo much to do in Azure. This presents a problem with clutter. Since I don’t use all of the features, I find the “menu” of options to be pretty noisy. But the good news is, that is an easy problem to solve.


To the left I’ve pasted a screenshot of the Azure Portal’s side menu (actually, that is only part of it). You’ll note that the items on that list are shown as “favorites”. But I didn’t favorite them! With a few clicks I can clean this up.










Just click “All services” and you can see the complete list. The list is pretty long but I’ve included a screenshot of some of it below:


From this screen you can easily select which items really are your favorites. That will immediately reduce the size of the side menu. In addition, you will find a TON of other options that were not displayed on the favorites list originally. That’s a little depressing because it shows that there is even more to learn in Azure than I first thought. But I guess that is a good problem to have.

But wait, there’s more!



Next, notice that as you hover over each item in the favorite list, you will see an icon indicating that you can grab it. If you do, you can drag the item up or down in the list.








When I am done selecting favorites and moving them around, I am left with a menu that makes it really easy for me to find what I need. No noise. Only the items I want in the order I want them. Now I can get to work!


Not a lot has changed with LINQ over the years. But I still find that developers aren’t completely familiar with the differences with some of the methods. In this post I’ll show the differences between:

  • Single()
  • SingleOrDefault()
  • First()
  • FirstOrDefault()

Of course these methods are similar but there are times when using the wrong one could lead to big problems with your application. The obvious similarity between these methods is that they are meant to return a single item. This is quite different from methods like Where() which returns a collection of items.

Now let’s focus on the differences.

I have noticed that in most cases, developers tend to use First() as the go to method for returning a single item from a collection. In my opinion, this is a bad idea. I tend to use Single() more often but of course there are times when each is appropriate. Here’s why…

Let’s start with a data set to work from. Here are some members of two great bands:

	List<Person> list = new List<Person>();
	list.Add(new Person {Id = 1, FirstName = "John", LastName = "Lennon"});
	list.Add(new Person {Id = 2, FirstName = "Paul", LastName = "McCartney"});
	list.Add(new Person {Id = 3, FirstName = "George", LastName = "Harrison"});
	list.Add(new Person {Id = 4, FirstName = "Ringo", LastName = "Starr"});
	list.Add(new Person {Id = 5, FirstName = "Jimmy", LastName = "Page"});
	list.Add(new Person {Id = 6, FirstName = "Robert", LastName = "Plant"});
	list.Add(new Person {Id = 7, FirstName = "John", LastName = "Bohnam"});
	list.Add(new Person {Id = 8, FirstName = "John Paul", LastName = "Jones"});

Let’s assume that the Id field is unique.

First, the method Single()

If I want to select a user by Id, I could use Single()

Person x = people.Single(p => p.Id == 1);

That will return the Person object for John Lennon.

For Single, the big difference comes when things aren’t as I expect them to be. Consider the following examples.

Person x = people.Single(p => p.Id == 9);

In this case, there is no person with an Id of 9. So Single() will throw an exception: “Sequence contains no matching element”.

Here’s another scenario

Person x = people.Single(p => p.FirstName == "John");

This too will throw an exception. This time it is “Sequence contains more than one matching element”.

So which is the best to use? It really depend on the situation. Often when you are selecting an item by Id, it is because you already know the Id. And if you do, I think it is safe to expect that the object with that Id exists. So I use Single(). In this case, the exception will be thrown if the user doesn’t exist but maybe that is ok because exceptions are for when things go wrong and in this case, something must have gone wrong. I also showed using Single(p => p.FirstName == “John”). But why would I do that? What reason could I have for selecting a Single item by a field that is not unique? Was I just curious to know if we had any Johns in the system? Would I have been better off with Any(p => p.FirstName == “John”) that returns a boolean?

Another option is SingleOrDefault()

Person x = people.SingleOrDefault(p => p.Id == 1);

This too will return the object for John Lennon.

Person x = people.SingleOrDefault(p => p.Id == 9);

SingleOrDefault() is safer. This time instead of an exception, x will be Null. Of course, as the developer, only I can decide which is better (Single or SingleOrDefault). It really depends on what I expect to happen and what other code exists to deal with unexpected results.

Person x = people.SingleOrDefault(p => p.FirstName == "John");

And SingleOrDefault() will still throw an exception if there is more than one “John”: “Sequence contains more than one matching element”

Next, a look at First() and FirstOrDefault()

Often, First() will give similar results but I find it misleading and using First() where inappropriate may actually hide problems. Consider the following:

Person x = people.First(p => p.Id == 1);

This too returns the object John Lennon.

Seems like everything is fine. But what if our data was bad. What if somehow we had two people with Id 1. Before you say “that would never happen”, think about some of the systems that you have supported. What if there was a mistake in the data entry validation? What if there was a bad import. My point is, it could happen. So now, if we use First(), we will get the first item in the collection that has the matching Id. It seems to me like in this case, I’d rather have Single throw an exception for me!

Unlike Single(), First() will NOT throw an exception if there is more than one matching element. Consider this:

Person x = people.First(p => p.FirstName == "John");

You can’t just assume that the result is John Lennon. It could depend on your data source and how the data was entered. Also, if a statement also had an OrderBy()

Person x = people.OrderBy(o => o.LastName).First(p => p.FirstName == "John");

Now I’m getting John Bohnam.

Yes, there are definitely cases when this is OK. But most of the time, I’d bet it is not. Why would I ever want the First() John?

Person x = people.FirstOrDefault(p => p.FirstName == "John");

This would have the same result as above. I could get John Lennon or John Bohnam depending on other factors.

Person x = people.FirstOrDefault(p => p.FirstName == "Pete");

Here, I get Null again (no exception). Sorry Pete Best, you’re not in the list.

So which to use?

There are circumstances for all of these. It’s great that we have 4 options. The important part is that as the developer, you understand that these are different. Please just don’t fall back on First() and use it all the time. Think about which is right for the circumstances you have at the moment.

One last tip

These statements may work correctly but they are just wasting keystrokes. I always say “less is more” with code.

Person x = people.Where(p => p.Id == 1).Single();
Person x = people.Where(p => p.Id == 1).First();

Please don’t do that. It’s much simpler to just say:

Person x = people.Single(p => p.Id == 1);
Person x = people.First(p => p.Id == 1);