I’ve seen lots of questions recently regarding if/how deployment of ASP.NET Core applications changed from previous versions of ASP.NET. The good news is many of the old capabilities exist, although you will likely have to adjust your deployment processes to utilize them. In this post, I will cover how to deploy an ASP.NET Core application to a WebDeploy package.

ASP.NET Core Web Publishing

Sayed Hashimi wrote a great article explaining how web publishing works in Visual Studio 2015 with ASP.NET Core projects. The good news is there are now 3 different extension points where we can customize the publish/deployment process.

Although ASP.NET Core projects don’t have the traditional .csproj project file, MSBuild is still used to kickoff the process (with VS or your CI process) and calls the appropriate dotnet commands behind the scenes. A PowerShell script is added by default with each new publish profile as well as one of the new extension points.

The ASP.NET Core updates for Visual Studio 2015 also include brand new MSBuild .targets files for deploying ASP.NET Core applications. Most of the meat is in the Microsoft.DotNet.Publishing.targets file.

DeployOnBuild Property

In previous versions of ASP.NET you typically initiated the publish process by adding the /p:DeployOnBuild=true as an MSBuild argument in your build. Depending on how your publishing your ASP.NET Core project that may have mixed results. For example, if you create a publish profile for creating a WebDeploy package for a ASP.NET Core project that has dependencies on other .NET Core libraries you can get errors:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Publishing.targets(149,5): error : Can not find runtime target for framework '.NETStandard,Version=v1.6' compatible with one of the target runtimes: 'win7-x64'. Possible causes: [D:\GitHub\AcmeApp.NET\src\AcmeApp.NET.Domain\AcmeApp. NET.Domain.xproj] C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Publishing.targets(149,5): error : 1. The project has not been restored or restore failed - run `dotnet restore` [D:\GitHub\AcmeApp.NET\src\AcmeApp.NET.Domain\AcmeApp.NET.Domain.xproj] C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Publishing.targets(149,5): error : 2. The project does not list one of 'win7-x64' in the 'runtimes' section. [D:\GitHub\AcmeApp.NET\src\AcmeApp.NET.Domain\AcmeApp.NET.Domain.xproj] C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Publishing.targets(149,5): error : 3. You may be trying to publish a library, which is not supported. Use `dotnet pack` to distribute libraries. [D:\GitHub\AcmeApp.NET\src\AcmeApp.NET.Domain\AcmeApp.NET.Domain.xproj]

In this case, the dotnet publish command is attempting to publish the .NET Core library but libraries are intended to be packaged not published according to the .NET Core team.

If you don’t have any .NET Core library project references, this would build and publish without error. So it depends on your project and how your publishing.

WebDeploy Packaging for ASP.NET Core

We can still create a WebDeploy package for our project with a .NET Core library reference by running the PackagePublish target from the commandline instead of setting the DeployOnBuild property to true.

D:\GitHub\AcmeApp.NET\src\AcmeApp.NET.Web>"c:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild" /t:PackagePublish /p:PublishProfile=Package

This will skip trying to publish the library project and instead only publish the web project thus avoiding the above error.

The Publish Profile can be created using the VS Web Publish dialog as described in my previous post Deploy ASP.nET Core 1.0 (RTM) to Azure App Service. The following is an example of the .pubxml generated for a Package publish:

<?xml version="1.0" encoding="utf-8"?> <!-- This file is used by the publish/package process of your Web project. You can customize the behavior of this process by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121. --> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <WebPublishMethod>Package</WebPublishMethod> <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> <LastUsedPlatform>Any CPU</LastUsedPlatform> <SiteUrlToLaunchAfterPublish /> <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> <ExcludeApp_Data>False</ExcludeApp_Data> <PublishFramework>netcoreapp1.0</PublishFramework> <UsePowerShell>True</UsePowerShell> <DesktopBuildPackageLocation>bin\debug\package.zip</DesktopBuildPackageLocation> <PackageAsSingleFile>true</PackageAsSingleFile> <DeployIisAppPath /> </PropertyGroup> </Project>

Notice above the DesktopBuildPackageLocation node which specifies where to place the package file. You can manually edit this to be more flexible by referencing other MSBuild properties. For example,

<DesktopBuildPackageLocation>bin\$(Configuration)\$(MSBuildProjectName).zip</DesktopBuildPackageLocation>

This will be overwritten however if you open the publish profile via the VS publish dialog. This isn’t typically a problem for us because we rarely use the VS publish dialog once we have a good CD pipeline.

Building via VSTS/TFS

We can also create the package via our CI process by adding the same MSBuild arguments to our Visual Studio Build task:

This task will output a WebDeploy package so we can deploy the same exact package to multiple environments from our Release Definition.

Feedback

Please let me know if this post was helpful or if you have further questions that I can help resolve. You can leave a comment below or start a conversation on Twitter or Reddit.