How to deploy ASP.NET Core sites using Teamcity to Azure/IIS

… or just command line

Sam Sperling
Monkii
7 min readOct 26, 2016

--

On ASP.NET Core

We just decided to give ASP.NET Core a go to see whether it’s ready to be used in a production environment. We’ve all waited such a long time for the final release, and since it’s been out for a few month… It was worth investing a bit of time to find those nitty gritty little details that the standard tutorials neatly jumps over.

I highly encourage you to do the same! Just take a few hours to read through the documentation, which I found very good and helpful:

In case you haven’t heard, the changes are huge. But good huge! Remember that ASP came out in 2002! The internet was a very different place then. But as with any system coming of age, things are carried along to ensure legacy support which over time ends up with a lot of junk that clogs the system. Hence the push to basically start from scratch and rethink everything for the Web of 2016+.

Best of all we can now have our front-end devs work on ASP.NET core projects running VS code on their Macs, which is a huge win for us.

After reading through the documentation I was very pleased with what I saw, and starting with Visual Studio 2015 was surprisingly easy. The new structure is in every way a big improvement.

The hurdle: automated publishing

The big hurdle came when I setup our continuous integration. I’ve been using TeamCity for a while now and thanks to its versatility I got it working, but only after a lot our trial and error. The whole publish process of ASP.NET Core still seems pretty new to the internet. So hopefully this will help others avoiding a lot of time wasted guessing how ASP.NET Core publishing works through TeamCity or command line.

Documentation on publishing ASP.NET Core

Microsoft has dedicated an entire section to Publishing & Deployment which is definitely worth the read. Especially the section how Web Publishing In Visual Studio Works was very helpful and crucial to figure this out.

It misses a crucial aspect. The article mentions the ‘[ProfileName].ps1’ for publishing but it fails to describe, how to use it.

Process

This is the process in one picture:

Publish profiles

I love, that Visual Studio provides the ability to create and manages publish profiles, something we’ve enjoyed not just with Core but for a few years now. Hooking into MSBuild and MSDeploy, it’s a very powerful tool to manage all sorts of different deployments, whether it’s development, staging and production environment, or other environments, whilst applying custom web.config transformations out of the box. Note that web.configs won’t be too useful anymore with Core but there are new ways… :)

In case you’ve never used them, just right click your project in VS and pick ‘Publish…’ an import for instance you Azure publish profile. More details can be found here: How to: Deploy a Web Project Using One-Click Publish in Visual Studio

VS Code

I don’t know how this process of creating / importing a publish profile works when using Visual Studio code. For now our VS Code developers rely on at least a single installation of VS Community (or higher) to create those profiles. Unless you want to hand code those files ;)

TeamCity Build Configuration

This is what I found to be a good way of setting it up in TeamCity:

  1. Create Template “ASP.NET Core Build Configuration” with 3 build steps:
    * Restore (dotnet core)
    * Build & Publish (dotnet core)
    * Deploy(via Powershell)
  2. Create a build configuration based on the template for each environment.
  3. Customize build config for version control etc.

First you’ll want to install the TeamCity .Net Core Plugin:

Binaries are here: https://teamcity.jetbrains.com/repository/download/TeamCityDotnetCorePluginBuild/.lastSuccessful/dotnet-core-plugin.zip?guest=1

Creating a ‘ASP.NET Core Build Configuration’ Template

I will assume, that anyone reading this post is familiar with TeamCity, to keep it simple.

[I have an extra step for managing the version number so don’t get confused by seeing 4 steps in the screenshots instead of 3]

  1. Create a buildstep called “Restore (dotnet core)” with the following settings:

2. Create a buildstep called “Build & Publish (dotnet core)” with the following settings:

3. Create a buildstep called “Deploy(via Powershell)” with the following settings:

This is the actual powershell script:

.\%Deployment.PublishProfile.Name%-publish -packOutput '%system.teamcity.build.checkoutDir%\publish' -pubProfilePath '%Deployment.PublishProfile.Name%.pubxml' -publishProperties @{'username' = '%Deployment.PublishProfile.Username%''Password' = '%Deployment.PublishProfile.Password%''AllowUntrustedCertificate' = $%Deployment.AllowUntrustedCertificate%'AuthType' = 'Basic'}

Adding the correct ‘publishProperties’ to the command is key here, and took me a long time to figure out (debugging through the publish-module.psm1). Especially since it doesn’t seem to be documented anywhere.

4. Enable Failure Conditions on errors logged

By default if the powershell script fails, it won’t be interpreted as a build fail. So you have to enable that in the ‘Failure Conditions’ section:

Create a build configuration based on the template for each environment

Since we’ve introduced 4 configuration parameters with the deployment powershell script creating a new build configuration that’s based on our template will pull up the following form.

Set parameters as follows:

  • Deployment.AllowUntrustedCertificate
    Set to false when deploying to a public server. Set to false if the deployment server is internal and doesn’t have a publicly valid certificate.
  • Deployment.PublishProfile.Name
    Name of the publish profile. E.g. Production
  • Deployment.PublishProfile.Password
    Publish password. For Azure you can find the password in the publish profile as downloaded from the Azure portal
  • Deployment.PublishProfile.Username
    Publish user. For Azure you can find the username in the publish profile as downloaded from the Azure portal

Customize build config for version control etc.

I generally have different environments feed of different branches to allow for hotfixes etc. based on Gitflow.

If that’s not required there is obviously room to simplify things.

So make sure you setup the Version Control Settings for each build configuration. And triggers for continuous integration.

The parameters should all be set on the initial creation screen. But if you want to double check or modify them, here is a little guide:

For Azure

For an Azure configuration make sure you set the AllowUntrustedCertificate to false, the rest as explained above:

For your internal IIS

For an your internal IIS I think it’s permissible to set the AllowUntrustedCertificate to true, the rest as explained above:

Internal IIS issues

Setting up deployment to our internal IIS has some issues!

I keep getting this error:

Exception calling “.ctor” with “1” argument(s): “Invalid URI: The format of the URI could not be determined.”At D:\TeamCity\BuildAgent\temp\buildTmp\powershell4704007462429846107.ps1:1

Which after some debugging turned out that the underlying problem stems from the MSDeploy.exe command:

C:\code\TestSite\src\TestSiteWeb\Properties\PublishProfiles>”C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe” -source:manifest=’C:\Users\Sam\AppData\Local\Temp\PublishTemp\obj\publish\SourceManifest.xml’ -dest:manifest=’C:\Users\Sam\AppData\Local\Temp\PublishTemp\obj\publish\DestinationManifest.xml’,ComputerName=’https://DevServer:8172/msdeploy.axd?site=TestSite',UserName='SecretUser',Password='SecretPassword',IncludeAcls='False',AuthType='Basic' -verb:sync -enablerule:AppOffline -retryAttempts:20 -allowUntrustedInfo: Using ID ‘83c00ac0–8a00–24cb-b61f-1094ba00008c’ for connections to the remote server.Info: Adding sitemanifest (sitemanifest).Info: Adding IIS Application (TestSite)Error Code: ERROR_USER_NOT_AUTHORIZED_FOR_IISAPPMore Information: Could not complete an operation with the specified provider (“iisApp”) when connecting using the Web Management Service. This can occur if the server administrator has not authorized the user for this operation. iisApp http://go.microsoft.com/fwlink/?LinkId=178034Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_USER_NOT_AUTHORIZED_FOR_IISAPP.Error count: 1.

I wish I could tell I resolved it, but I haven’t. I spent a lot of time looking at all the permissions but without look. And Microsoft hasn’t gotten back to me about it. But I’ll keep you updated.

For some people there seems to be an easy solution: Stackoverflow, serverfault.com

Unfortunately they haven’t worked for me, and I don’t seem to be the only one.

As a workaround you can just setup the dotnet publish command to publish the files straight into your IIS website folder.

Thoughts

I really like dotnet core, even though the deployment part of it still needs a little love and we’re waiting for a lot of open source projects to support it. But that will probably still take some time, due to the significant changes, but I’m confident that 2–3 years from now we’ll all be pretty happy that it happened.

Please let me know how you are finding dotnet core! Love it hate it? How does it integrate into your devops pipeline?

Thanks to Monkii

… for generously providing time and support to investigate dotnet core on a production project. :)

Update #1

Looks like Microsoft is still making changes to their Core SDK. In addition to the dotnet.exe, MSBuild will be come a cross platform command:

… that might change the deployment process again :)

Update #2

After talking to TeamCity they were so kind to write up a Teamcity & .Net Core post:

--

--

Sam Sperling
Monkii
Writer for

Master of Technology & Strategic / People-Centric Leader | AI and Machine Learning Enthusiast. Head of Engineering at Kolmeo. Proud father of 4.