Enterprise Azure ARM Templates

Lately I’ve given many workshops to all kinds of customers of my employer Xpirit about the automatic deployment of Azure resources. Mainly with VSTS.

I noticed customers would like to have ready to use ARM Templates.

resource-groupOf course there are the valuable Azure Quickstart templates (or via the portal)  which I use a lot. Sometimes these templates offer a complete solution. Mainly I use these templates to have, as the name tells, a quick start, for creating ARM templates fast.

Another way to get the ARM Template you wish is to download it after creating a resource through the Azure portal. These generated ARM Templates are nice for a reference, but are too generic. To use these templates in your automatic deployment pipeline you will have some work to do.

Besides this, I create ARM Templates a lot lately. For demo’s and for the Dutch Azure Meetup. I would like to reuse the templates easier myself and offer these templates to the community.

For these reasons I decided to start collecting the ARM Templates I have used to create resources in Azure. You can find the ARM Templates here. The templates are meant to be used right away.

For now ARM templates can be used per Resource type. You can use two types of ARM templates for the same resource.

One standard version where the user of the template decides what the name of the created resource will be.

Most enterprises I’ve visited don’t want to think about the way resources are named in Azure, but wants a consistent way of naming. When it’s possible to pass a name to a resource, they will end up with all kinds of naming conventions. For this reason the ARM templates are offered with a namingconvention also. This version of the Enterprise ARM templates passes metadata to tags of the resources also.

Infrastructure as Code and VSTS

Written by Peter Groenewegen and Pascal Naber for the Xpirit Magazine

Your team is in the process of developing a new application feature, and the infrastructure has to be adapted. The first step is to change a file in your source control system that describes your infrastructure. When the changed definition file is saved in your source control system it triggers a new build and release. Your new infrastructure is deployed to your test environment, and the whole process to get the new infrastructure deployed took minutes while you only changed a definition file and you did not touch the infrastructure itself.

Does this sound like a dream? It is called Infrastructure as Code. In this article we will explain what Infrastructure as Code (IaC) is, the problems it solves and how to apply it with Visual Studio Team Services (VSTS).
Read more →

VSTS Task to create a SAS Token

The Create SAS Token task creates a SAS Token which can be used to access a private Azure Storage Container. The task also gets the StorageUri. Both variables can be used in subsequent tasks, like the Azure Resource Group Deployment task. This is the first task of the Infrastructure as Code serie.

The Task can be found in the marketplace and added to your VSTS account. The code is open source and can be found on GitHub.

Prerequisites for the sample

In this sample I’m executing an ARM template which uses linked ARM Templates. These linked ARM Templates are stored in a private Azure Storage Container. I will be using the Azure Resource Group Deployment task to deploy the parent ARM Template.

The Azure Storage Container looks like this:

AzureStorageContainer
Read more →

Create an Azure Service Principal and a VSTS ARM Endpoint

25-8-2016: Update because the UI to create a Service in VSTS changed

When you want to access Azure from VSTS there are multiple possibilities. It’s for example possible in VSTS to configure an Azure Classic Endpoint and after that configure the endpoint with credentials or with a certificate. The ARM way is to add an Azure Resource Manager Endpoint. To configure this you will need the settings of an Azure Service Principal. This blogpost tells you how to create both the Service Principal in Azure and the ARM Endpoint in VSTS.

Azure Service Principal

You can create an Azure Service Principal on multiple ways. Here you can read how to add an Azure Service Principal through the Classic Azure Portal. It’s also possible to add an Azure Service Principal through PowerShell. This PowerShell script can be used to create a Principal that has access to the whole subscription. I prefer to create a Service Principal that has access to a single ResourceGroup only. Here you can find the slightly changed script which support ResourceGroup access. When you run the script, the output will look like the following picture. Later on you will need the last five parts to create an ARM Endpoint in VSTS.

output
Read more →

VSTS Task to deploy AppSettings and ConnectionStrings to an Azure WebApp

The Azure WebApp Configuration task reads VSTS variables and adds those as AppSettings and ConnectionStrings to an Azure WebApp. The task also supports Slot Settings. The task can be linked to a web.config to validate if all AppSettings and ConnectionStrings in the web.config exists as VSTS variable.

The Task can be found in the marketplace and added to your VSTS account. The code is open source and can be found on GitHub.

Naming convention

The task uses naming conventions in the VSTS variables to deploy appsettings and connectionstrings to an Azure WebApp. If you like as a Slot Setting. The value of the VSTS variable is used for the value for the appsetting or in case of a connectionstring, the connectionstring.

The following naming conventions rules are supported:

  • The name of a variable for an appsetting must start with appsetting.
  • The name of a variable for a connectionstring must start with connectionstring.
  • The type of database should be added in the namingconvention as stated in the following table.
  • For a slotsetting the convention .sticky must be used.

The table below shows some examples:

Type Example VSTS variable name
appsetting appsetting.mysetting
appsetting with slotsetting appsetting.mysetting.sticky
connectionstring to SQL Server connectionstring.myconnectionstring.sqlserver
connectionstring to SQL Azure connectionstring.myconnectionstring.sqlazure
connectionstring to custom connectionstring.myconnectionstring.custom
connectionstring to MySQL connectionstring.myconnectionstring.mysql
connectionstring with slotsetting connectionstring.myconnectionstring.sqlserver.sticky

Steps to use and configure the task

  1. Install the task in your VSTS account by navigating to the marketplace and click install. Select the VSTS account where the task will be deployed to.
  2. Add the task to your release by clicking in your release on add a task and select the Utility category. Click the Add  button on the Apply variables to Azure webapp task.
    addtask
  3. Configure the task. When the task is added the configuration will look like this:
    cleantask
    All yellow fields are required.
    – Select an AzureRM subscription. If you don’t know how to configure this. Read this blogpost.
    – Select the web app name.
    – Select the resourcegroup.
    – If you want to deploy to a Deployment slot, check the Deploy to Slot checkbox and select the Slot.
    – If you want to validate the VSTS variables against the appSettings and ConnectionStrings in the web.config of the application you deploy, then select the web.config. Otherwise uncheck the Validate variables checkbox.
    – When you want validation, you can choose how the task should behave when it finds incorrect variables. Default behavior is that the task will fail with an error. This results in a failed Release  and the variables will not be deployed.
    The other validation result action is  to only get a warning. The variables will be deployed to Azure.
    – By default all existing AppSettings and ConnectionStrings in Azure are overwritten by the variables in the release. When you don’t want this, but you want to preserve your appsettings or connectionstrings in your WebApp, then uncheck the Overwrite existing configuration checkbox.
  4. The web.config of your application is not being used to deploy variables to Azure. If you have configured validation, the keys of the appSettings and the names of the ConnectionStrings are used to validate if there are VSTS variables available for these settings. The web.config in this sample looks like this:
    webconfig
  5. Add variables that match the names of the variables in the AppSettings and ConnectionStrings. Also apply the namingconventions for the VSTS variables.
    vstsvariables
  6. Instead of configuring Release variables as in step 5, you can also configure Environment variables. This step shows you how you can configure the release in VSTS to support multiple environments. In this sample each environment will have the same appsettings and connectionstrings. But the value of those differentiate.
    After creating the Environments, configure variables per environment. Just like step 5, just add the keys and the values. ConfigureVariablesPerEnvironment
    To see the Environment variables at a glance, select the Environment variable view as you can see in the following picture:
    SelectEnvironmentVariables
    When you have configured all Environments, you will see an overview like the following:
    VariablesPerEnvironment
  7. When you run the release, the settings will be deployed to Azure. In this sample it looks like this:
    Note that the hidden value in VSTS is visible now in Azure.
    azure

Started Dutch Azure Meetup

Logo Meetup
This week Marco Mansi, Sander Molenkamp and I started the Dutch Azure Meetup: http://www.meetup.com/Dutch-Azure-Meetup/

Azure offers a lot of services and features, and this grows almost daily. It’s hard to be up-to-date on all the Azure features. This meetup gives you the opportunity to learn about Azure in a practical way.

We want to offer a platform for Azure enthusiasts, where you can get hands-on with the technology, talk with and learn from each other. The meetup will not handle customer cases in theory but instead we talk about deep technical details, real world experiences and best practices.

Our first meetup is planned for the 2nd of June and is all about Azure Container Service:

Join the first Dutch Azure Meetup!

Docker is taking the world by storm and Microsoft Azure Container Service is where Azure and Docker meet!

During this first meetup Mark van Holsteijn will give you a brief introduction into Docker and Microsoft Container Service.After which you will have ample opportunity to get hands-on with Docker, Marathon, Azure and ASP.NET core.

We will show you how Azure Container Service provides an excellent platform for creating cross-cloud applications.

About the speaker

Mark van Holsteijn is Principal Consultant at Xebia specialized in cloud software architectures with open-source technologies.

Agenda

18:00: Dinner

18:45: Word of welcome Dutch Azure Meetup

18:50: Azure Container Service (by Mark van Holsteijn)

19:30: Hands-on with Docker and Azure Container Service

Exception with the creation of a Visual Studio Virtual Machine in Azure without MSDN subscription

My previous blogpost shows you how to create a Visual Studio Development Virtual Machine in Azure. When you don’t have a MSDN subscription it turns out you get an exception when you create the Virtual Machine, based on the image with Visual Studio 2015, Azure SDK 2.9 and Windows 10. The exception comes up both in the portal and with PowerShell.

In the Portal

It is possible to see all Virtual Machines with Visual Studio including the Virtual Machines with Windows 10. But if you try to select the image to create a Virtual Machine, you will get the message: Looks like you need an MSDN subscription.

portal error

With PowerShell

Of course it’s not possible in PowerShell also to create a Virtual Machine based on image VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64. When you run my PowerShell script on a non-MSDN subscription, you will get the following exception:

New-AzureRmResourceGroupDeployment : 04:42:37 - Resource 
Microsoft.Compute/virtualMachines 'azurebootcamp1' failed with message 
'The platform image 'MicrosoftVisualStudio:VisualStudio:
VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64:latest' is not available. 
Verify that all fields in the storage profile are correct.'
At Deploy-VMs.ps1:29 char:5
+ New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $Templat ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
 + FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureResourceGroupDeploymentCommand

The solution

The new portal does show all images with Visual Studio, both Windows 10 and Windows 2012. So it shows also the images that can’t be used to create a Virtual Machine based on the subscription.

It turns out that the classic portal shows only images that actually can be used to create a Virtual Machine. The classic portal shows Visual Studio images with Windows 2012. Not the images with Windows 10 which can’t be used.

The next step was to select a Windows 2012 image with Visual Studio in the new portal instead of a Windows 10 image. And it turns out that this works!

Now it’s a little step to do it programmatically also. Just change the parameter for the image. My previous blogpost shows how to get a list of all SKU’s with Visual Studio. The correct image for a non-msdn subscription that works for us is:
VS-2015-Ent-VSU2-AzureSDK-29-WS2012R2

 

Create a Visual Studio Virtual Machine on Azure programmatically

There are multiple possibilities to create a development environment with Visual Studio on Azure. It can be created manually in the Azure Portal or programmatic with PowerShell.

Manually in the Azure Portal

You can create a development environment in the Azure Portal within minutes . Select the image with Visual Studio in the Azure Portal that best suites your requirements. At the time of writing, the latest version in the Azure Portal that can be selected is Visual Studio 2015 with update 2 and Azure SDK 2.9. It’s easy to select an image in the Portal, now let’s see how this can be done in code.

Virtual Machines - Microsoft Azure

Programmatic with PowerShell

When you want to create a Virtual Machine programmatically, PowerShell is your friend together with an ARM template.

This ARM template for example, will help you creating an image with Visual Studio. The ARM template contains a list of SKU’s to choose from, but unfortunately the Visual Studio 2015 with update 2 and Azure SDK 2.9. version is not present in the list of SKU’s. How should you know what SKU you’ve got to pass as a parameter? The name of the SKU is not visible in the Azure Portal.

This article tells you the steps to get a SKU. When you use PowerShell, the Cmdlets Get-AzureVMImagePublisher, Get-AzureVMImageOffer and Get-AzureVMImageSku mentioned in the article are not available. You should use the RM versions of the Cmdlets.

To get the complete list of all images that offers Visual Studio execute the following line:

Get-AzureRmVMImageSku -Location West Europe -Publisher “MicrosoftVisualStudio” -Offer “VisualStudio” | Select Skus

The result is the following list of SKU’s that offer Visual Studio.

Skus
 ----
 2013-Community-Update-4-ws2012-az25-ntvs10
 2013-Community-Update-4-ws2012-az26
 2013-Community-Update-4-ws2012-az26-cor31
 2013-Premium-Update-4-win81
 2013-Premium-Update-4-win81n-az26
 2013-Premium-Update-4-ws2012-az26
 2013-Professional-Update-4-ws2012-az26
 2013-Ultimate-Update-4-win81
 2013-Ultimate-Update-4-win81n-az26
 2013-Ultimate-Update-4-ws2012-az26
 2015-Community-RC
 2015-Enterprise-RC
 2015-Enterprise-Win10Tools
 2015-Professional-RC
 CoreCLR
 VS-2013-Comm-VSU5-AzureSDK-2.8-Win8.1-N-x64
 VS-2013-Comm-VSU5-AzureSDK-2.8-WS2012R2
 VS-2013-Comm-VSU5-Cordova-CTP3.2-AzureSDK-2.8-WS2012R2
 VS-2013-Community-VSU5-AzureSDK-2.7-Win8.1-N-x64
 VS-2013-Community-VSU5-AzureSDK-2.7-WS2012R2
 VS-2013-Community-VSU5-Cordova-CTP3.2-AzureSDK-2.7-WS2012R2
 VS-2013-Prem-VSU5-AzureSDK-2.8-Win8.1-N-x64
 VS-2013-Prem-VSU5-AzureSDK-2.8-WS2012R2
 VS-2013-Premium-VSU5-AzureSDK-2.7-SQL-WS2012R2
 VS-2013-Premium-VSU5-AzureSDK-2.7-Win8.1-N-x64
 VS-2013-Premium-VSU5-AzureSDK-2.7-WS2012R2
 VS-2013-Ultimate-VSU5-AzureSDK-2.7-SQL-WS2012R2
 VS-2013-Ultimate-VSU5-AzureSDK-2.7-Win8.1-N-x64
 VS-2013-Ultimate-VSU5-AzureSDK-2.7-WS2012R2
 VS-2013-Ultimate-VSU5-AzureSDK-2.8-Win8.1-N-x64
 VS-2013-Ultimate-VSU5-AzureSDK-2.8-WS2012R2
 VS-2015-Com-VSU1-AzureSDK-2.8-WS2012R2
 VS-2015-Comm-AzureSDK-2.8-Cordova-Win8.1-N-x64
 VS-2015-Comm-AzureSDK-2.8-WS2012R2
 VS-2015-Comm-AzureSDK-2.8-WS2012R2.1
 VS-2015-Comm-AzureSDK-2.8-WS2012R2.2
 VS-2015-Comm-VSU1-AzureSDK-2.8-W10T-1511-N-x64
 VS-2015-Comm-VSU1-AzureSDK-2.8-W10T-N-x64
 VS-2015-Comm-VSU1-AzureSDK-2.8-WS2012R2
 VS-2015-Comm-VSU1-AzureSDK-2.8-WS2012R2.1
 VS-2015-Comm-VSU2-AzureSDK-29-W10T-N-x64
 VS-2015-Comm-VSU2-AzureSDK-29-WS2012R2
 VS-2015-Community-AzureSDK-2.7-Cordova-Win8.1-N-x64
 VS-2015-Community-AzureSDK-2.7-W10T-Win10-N
 VS-2015-Community-AzureSDK-2.7-WS2012R2
 VS-2015-Ent-AzureSDK-2.8-Cordova-Win8.1-N-x64
 VS-2015-Ent-AzureSDK-2.8-WS2012R2
 VS-2015-Ent-AzureSDK-2.8-WS2012R2.2
 VS-2015-Ent-VSU1-AzureSDK-2.8-W10T-1511-N-x64
 VS-2015-Ent-VSU1-AzureSDK-2.8-W10T-N-x64
 VS-2015-Ent-VSU1-AzureSDK-2.8-WS2012R2
 VS-2015-Ent-VSU1-AzureSDK-2.8-WS2012R2.1
 VS-2015-Ent-VSU1-AzureSDK-2.8-WS2012R2.2
 VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64
 VS-2015-Ent-VSU2-AzureSDK-29-WS2012R2
 VS-2015-Enterprise-AzureSDK-2.7-Cordova-Win8.1-N-x64
 VS-2015-Enterprise-AzureSDK-2.7-W10T-Win10-N
 VS-2015-Enterprise-AzureSDK-2.7-WS2012R2
 VS-2015-Pro-AzureSDK-2.8-Cordova-Win8.1-N-x64
 VS-2015-Pro-VSU1-AzureSDK-2.8-W10T-1511-N-x64
 VS-2015-Pro-VSU1-AzureSDK-2.8-W10T-N-x64
 VS-2015-Pro-VSU1-AzureSDK-2.8-WS2012R2.2
 VS-2015-Professional-AzureSDK-2.7-Cordova-Win8.1-N-x64
 VS-2015-Professional-AzureSDK-2.7-W10T-Win10-N
 VS-Next-Preview-Ent-AzureSDK-2.9-W10-N
 VS-Next-Preview-Ent-AzureSDK-2.9-WS2012R2

 

In my case, I’m able to choose between Visual Studio Enterprise or Community, and choose between Windows 10 or Windows 2012 R2. I selected the following SKU:

VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64.

When you pass this SKU to the ARM template mentioned above, with the following script:

# Login to Azure
Login-AzureRmAccount

# Optionally select the correct subscription
Select-AzureRmSubscription -SubscriptionId "<YourSubscriptionId>"

# parameters to create a Visual Studio Image
$ResourceGroupName = "myresourcegroup"
$Location = "West Europe"
$VmName = "myVmName"
$vmAdminUserName = "myAdminUser"
$vmAdminPassword = "P@ssw0rd1"
$vmSize = "Standard_DS2"
$vmVisualStudioVersion = "VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64"
$VmIPPublicDnsName = "myPublicDnsName"

# Create the resourcegroup
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location -Verbose -Force -ErrorAction Stop 

# Execute the ARM template 
New-AzureRmResourceGroupDeployment -Name ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm') `
 -ResourceGroupName $ResourceGroupName `
 -TemplateUri https://raw.githubusercontent.com/azure/azure-quickstart-templates/master/visual-studio-dev-vm/azuredeploy.json `
 -TemplateParameterObject @{deployLocation=$Location;vmName=$vmName;vmAdminUserName=$vmAdminUserName;vmAdminPassword=$vmAdminPassword;vmSize=$vmSize;vmVisualStudioVersion=$vmVisualStudioVersion;vmIPPublicDnsName=$vmIPPublicDnsName} -Force -Verbose

You will get the following validation error:

New-AzureRmResourceGroupDeployment : InvalidTemplate: Deployment template validation failed: ‘The provided value ‘VS-2015-Ent-VSU2-AzureSDK-2
9-W10T-N-x64′ for the template parameter ‘vmVisualStudioVersion’ at line ’60’ and column ’31’ is not valid. The parameter value is not part o
f the allowed value(s): ‘VS-2015-Pro-VSU1-AzureSDK-2.8-W10T-1511-N-x64,VS-2015-Pro-AzureSDK-2.8-Cordova-Win8.1-N-x64,VS-2015-Ent-VSU1-AzureSD
K-2.8-WS2012R2,VS-2015-Ent-VSU1-AzureSDK-2.8-W10T-1511-N-x64,VS-2015-Comm-VSU1-AzureSDK-2.8-WS2012R2,VS-2015-Comm-VSU1-AzureSDK-2.8-W10T-N-x6
4,VS-2015-Comm-AzureSDK-2.8-Cordova-Win8.1-N-x64,VS-2013-Ultimate-VSU5-AzureSDK-2.8-WS2012R2,VS-2013-Prem-VSU5-AzureSDK-2.8-WS2012R2,VS-2013-
Comm-VSU5-Cordova-CTP3.2-AzureSDK-2.8-WS2012R2,VS-2013-Comm-VSU5-AzureSDK-2.8-WS2012R2′.’.
At line:16 char:1
+ New-AzureRmResourceGroupDeployment -Name ((Get-Date).ToUniversalTime( …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzureRmResourceGroupDeployment], CloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureResourceGroupDeploymentCommand

 

This is because there is a limited set of SKU’s available in the ARM template. To get around this you have to change the ARM template. First download the ARM template and save it with the name AzureDeploy.json. Add the missing SKU to the list of available SKU’s in the json (or delete them all, so there won’t be any validation on it).

Change the PowerShell script to execute the ARM template from locally:

# Login to Azure
Login-AzureRmAccount

# Optionally select the correct subscription
Select-AzureRmSubscription -SubscriptionId "<YourSubscriptionId>"

# parameters to create a Visual Studio Image
$ResourceGroupName = "myresourcegroup"
$Location = "West Europe"
$VmName = "myVmName"
$vmAdminUserName = "myAdminUser"
$vmAdminPassword = "P@ssw0rd1"
$vmSize = "Standard_DS2"
$vmVisualStudioVersion = "VS-2015-Ent-VSU2-AzureSDK-29-W10T-N-x64"
$VmIPPublicDnsName = "myPublicDnsName"

# Create the resourcegroup
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location -Verbose -Force -ErrorAction Stop

$TemplateFile = 'AzureDeploy.json'
$TemplateFile = [System.IO.Path]::Combine($PSScriptRoot, $TemplateFile)

# Execute the ARM template
New-AzureRmResourceGroupDeployment -Name ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm') `
-ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterObject @{deployLocation=$Location;vmName=$vmName;vmAdminUserName=$vmAdminUserName;vmAdminPassword=$vmAdminPassword;vmSize=$vmSize;vmVisualStudioVersion=$vmVisualStudioVersion;vmIPPublicDnsName=$vmIPPublicDnsName} -Force -Verbose

When you execute this PowerShell Script with the slightly changed ARM template, the image will be created on Azure.

Migrate TFS to Git

Maybe you’ve read about Git for a long time and use it for your private projects. Maybe you want to migrate your project’s TFS Version Control to Git, either with TFS Git or elsewhere, but don’t know how. Or maybe you’ve read Dennis Doomen’s post about ‘Why you should abandon TFS and adopt Git’ and though: ‘I really need to move over right now, but how?’ If you are using TFS you will probably have a history that you want to have in Git also.

This post is based on the post ‘TFS to Git migration: step by step’ from Natalia An which can be found here. Below is an up-to-date version of all the steps which works for our projects.

This post tells you how to migrate your TFS Version Control to Git while maintaining history, step by step. The migration takes along the history, but not the branches in TFS.

This post was not possible without the help of ALM MVP Terje Sandstrøm.

Prerequisites

The following tools will be used:

  1. Git for Windows https://git-scm.com/download/win
  2. Git TF
    1. You can use chocolatey to install this tool. Just follow the steps described here: https://chocolatey.org/
    2. Type:
      cinst Git-TF to install Git TF
    3. Check if Git TF is added to your System Path variables by executing the exe: git tf. The result should look like this:
      1 gittf
  3. I like to use Git Shell, which you can get by installing GitHub for Windows. https://windows.github.com/
  4. Optionally: IFix (from Terje Sandstrøm) can be used to update the ignore file. http://visualstudiogallery.msdn.microsoft.com/b8ba97b0-bb89-4c21-a1e2-53ef335fd9cb

Steps for the migration

  1. Open up a command prompt to the directory where your GIT repositories are located.
    By default, this is the path: c:users<username>sourcerepos
  2. Clone all files from TFS to Git while preserving history. The git repository will be created if it doesn’t exists.
    Type:

    git tf clone <tfs collection URL> <tfs team project path> <git repository name> --deep

    If you don’t want to bring along the history to Git. Than leave out the –deep parameter.
    2 clone

  3. Select the new repository by changing the directory.
    3 cd
  4. Update the gitignore file with the latest from github and add it to the repository. This can be done with Ifix or manually. When using ifix follow the following steps:
    1. Type:
      ifix gitignore –s –f
    2. Add the file to the repository:
      git add *
    3. Commit the file with a comment:
      git commit –m “updated gitignore”

      The result looks like this:
      4 gitignore

  1. Remove the old connection to TFS VC in the configuration of git
    1. Open the config file in directory .git.
    2. Make sure the file only contains the following information:
      5 config
  2. Cleanup the repository
    The gitignore file will prevent us from adding dll’s to the repo. Because of the use of nuget packages, we want to make sure there are no dll’s in our repository. If there are dll’s, delete them from the repository and history. If there are dll’s found. Also delete pdb’s. Finally we don’t want to have packages folders also in our repository.

    1. git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *.dll'

      6 indexfilter

    2. In this case no dll’s were found because the master is unchanged. So it was not needed to execute the following command in this sample to delete the pdb’s also.
      git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *.pdb’
    3. Delete the packages folders:
      git filter-branch --force --index-filter "git rm -rf --cached --ignore-unmatch packages"

      7 packages

    4. Clean up git and run garbage collection:
      git reflog expire --all
      git  gc --aggressive --prune
  1. If you want to make changes to the solution. It can be done in this step. In our case we are splitting the solution into multiple solutions. So we are deleting projects from the solution and instead of project references use nuget references.
  2. Add the local repository to the remote Git repository.
    1. Navigate to the directory of the repository
    2. Execute the following commands:
      git remote add origin <url of the remote git repo>
      git push –u origin –-all

      8 push

MVVM with Xamarin Classic: The Basics

Xamarin makes it possible to develop apps for multiple platforms (Windows Phone, iOS, Android). The downside to this, is the need to develop a view per platform with codebehind. This results in duplicate code throughout the solution. This could partially be avoided by using a Shared Library. This library can, for example, contain classes that offer functionality to consume webservices. The part that cannot be avoided is UI specific code. Another downside of this approach is the lack of testability because you need to create unittests per platform and also need to test UI codebehind. The classes in the code behind have too many responsibilities, this is not SOLID.

The standard architecture looks like this:

xamarindefaultarchitecture

This is where MVVM provides a solution.

When applying MVVM, a viewmodel is created for each unique screen in the application. The three views (one for each platform) are bound to the corresponding ViewModel. Therefor the codebehind becomes obsolete and can be deleted. The ViewModels are located in the Shared Library. With MVVM the architecture looks like this:

xamarinmvvmarchitecture

The testability and maintainability are improved in several ways:

  • Only one class, the ViewModel, has to be created and tested instead of three code behind classes.
  • The ViewModel has no platform specific UI code.
  • Separating logic from the view gives the ability to inject dependencies into the viewmodel. The ViewModels can be tested with mocks and/or stubs.

There are some issues to resolve:

  • The View and the ViewModel are loosely coupled. The View needs to be pointed to the corresponding ViewModel.
  • You have to choose a Dependency Injection framework.

It’s not needed to reinvent the wheel. There are multiple MVVM frameworks available that offer this and much more. Besides MvvmLight you can also use MvvmCross.

The next codesnippets show samples on how the code looks like before and after applying MVVM with MvvmCross.

Classic non-MVVM way of a View is shown.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:text="Previous"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/buttonPrevious"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true" />
    <Button
        android:text="Next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/buttonNext"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true" />
    <TextView
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textDescription"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp" />
</RelativeLayout>

The ‘code behind’ for the View. Notice the dependency to the TodoTaskService. The same kind of code should be programmed for other platforms also.

[Activity(Label = "Naber.Tasks.UI.Droid", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    Button buttonNext;
    Button buttonPrevious;
    TextView textDescription;
    TodoTaskService service = new TodoTaskService();
    IDataManager<TodoTask> data = null;
 
    protected async override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
                    
        SetContentView(Resource.Layout.Main);
 
        var tasks = await service.GetTodoTasksAsync();
        this.data = new DataManager<TodoTask>(tasks);
                  
        buttonNext = FindViewById<Button>(Resource.Id.buttonNext);
        buttonPrevious = FindViewById<Button>(Resource.Id.buttonPrevious);
        textDescription = FindViewById<TextView>(Resource.Id.textDescription);
 
        buttonNext.Click += buttonNext_Click;
        buttonPrevious.Click += buttonPrevious_Click;
 
        UpdateUi();
    }       
 
    void buttonPrevious_Click(object sender, EventArgs e)
    {
        data.MovePrevious();
        UpdateUi();                        
    }
 
    void buttonNext_Click(object sender, EventArgs e)
    {
        data.MoveNext();
        UpdateUi();            
    }
 
    private void UpdateUi()
    {
        textDescription.Text = data.Current.Description;                      
        buttonPrevious.Enabled = data.CanMovePrevious;
        buttonNext.Enabled = data.CanMoveNext;
    }
}

When using MvvmCross the Code Behind can be removed. The View supports data binding. The bold lines are added and takes care of binding the property of the control (first string) to the property or command on the ViewModel (second string).

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:text="Previous"
        local:MvxBind="Click PreviousCommand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/buttonPrevious"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true" />
    <Button
        android:text="Next"
        local:MvxBind="Click NextCommand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/buttonNext"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true" />
    <TextView
        local:MvxBind="Text Description"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textDescription"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp" />
</RelativeLayout>

The ViewModel is created in a shared library so all target platforms can use it. Notice there is no dependency to an instance of the TodoTaskService. It’s being injected. This can be configured in the Initialization of MvvmCross which is also reused code.

public class MainViewModel : MvxViewModel
{
    ITodoTaskService taskService;
    IDataManager<TodoTask> tasks;
 
    public MainViewModel(ITodoTaskService taskService)
    {
        this.taskService = taskService;
    }
 
    public async override void Start()
    {
        this.tasks = new DataManager<TodoTask>(await this.taskService.GetTodoTasksAsync());
        this.tasks.MoveFirst();
 
        Rebind();
        base.Start();
    }
 
    private void Rebind()
    {
        this.Description = this.tasks.Current.Description;
       
        NextCommand.RaiseCanExecuteChanged();
        PreviousCommand.RaiseCanExecuteChanged();
    }
 
    private string description;
 
    public string Description
    {
        get { return this.description; }
        set
        {
            this.description = value;
            RaisePropertyChanged(() => Description);
        }
    }   
    
    private MvxCommand nextCommand;
    public MvxCommand NextCommand
    {
        get
        {
            this.nextCommand = this.nextCommand ?? new MvxCommand(NavigateToNext, CanNavigateNext);
            return this.nextCommand;
        }
    }
 
    private bool CanNavigateNext()
    {
        return this.tasks.CanMoveNext;
    }
 
    public void NavigateToNext()
    {
        this.tasks.MoveNext();
        Rebind();
    }
 
    private MvxCommand previousCommand;
    public MvxCommand PreviousCommand
    {
        get
        {
            this.previousCommand = this.previousCommand ?? new MvxCommand(NavigateToPrevious, CanNavigatePrevious);
            return this.previousCommand;
        }
    }
 
    private bool CanNavigatePrevious()
    {
        return this.tasks.CanMovePrevious;
    }
 
    public void NavigateToPrevious()
    {
        this.tasks.MovePrevious();
        Rebind();
    }
}

This basic sample shows how to apply MVVM to Xamarin Classic. A SOLID way to develop business apps.

The full sample can be downloaded here.