Force 'dotnet publish' to publish dependencies using PublishWithAspNetCoreTargetManifest

February 23, 2018
Cover Image

I ran into a problem today doing an automated build for a ASP.NET Core 2 project and then trying to deploy the output.  From the command line, I ran "dotnet publish -o c:\temp\presidents" to build and publish the code for my ASP.NET Core web application.  Then I went to the directory that I just published to ('c:\temp\presidents') and tried to run it using "dotnet Benday.Presidents.WebUi.dll".

At this point, I'd expect that it would just run because I'd just done a 'publish' and that publish is supposed to create a deployable version of my ASP.NET Core app.  Right?  I mean that's what I think of when I do a publish.

The answer: Nope.  More precisely: Nope nope nope and more nope with an extra side of nope sauce for dipping and furthermore nnnnnnope.

Here's what I got.

Error: An assembly specified in the application dependencies manifest (Benday.Presidents.WebUi.deps.json) was not found: package: 'Microsoft.AspNetCore.Mvc.Abstractions', version: '2.0.2' path: 'lib/netstandard2.0/Microsoft.AspNetCore.Mvc.Abstractions.dll' This assembly was expected to be in the local runtime store as the application was published using the following target manifest files: aspnetcore-store-2.0.5.xml

The Heavy-Handed Fix

Hunting around on the internet(s), I saw a bunch of people mentioning that it works if you add false to your *.csproj file.

I added that and re-ran my dotnet publish and it fixed it.  All the required DLLs got published and my "dotnet Benday.Presidents.WebUi.dll" command ran the web app successfully.

But this seemed a little heavy-handed.

The More Lightweight, DevOps-Friendly Fix

Thanks to this thread on StackOverflow and a comment from Nate McMaster, there's an easier way to do this that doesn't require editing your csproj file.  Turns out that there's an undocumented /property command line option for "dotnet publish" that lets you pass msbuild variables in.  Supply the following /property value and it causes dotnet publish to publish all the dependencies.

dotnet publish -o c:\temp\presidents /property:PublishWithAspNetCoreTargetManifest=false

Now why do I think that this is more DevOps-friendly?  Well, when I'm doing a DevOps release pipeline, I want to build one time and then be done with it.  I want everything to be packaged up into something that I can easily deploy and I don't want my environment-specific releases to have to worry about finding and resolving dependencies.  Adding this /property:PublishWithAspNetCoreTargetManifest=false to my automated build gives me a nice clean easily-deployable output from my build.

PublishWithAspNetCoreTargetManifest With TFS Builds and VSTS Builds

If you create a build definition in Team Foundation Server (TFS) or Visual Studio Team Services (VSTS) for an ASP.NET Core project, the default definition template basically does the same thing as what you'd do on the command prompt.  It does a "dotnet restore", "dotnet build", "dotnet test", and then a "dotnet publish".  The last step is to do a "Publish Artifact" operation that publishes the output of the builds to TFS/VSTS where it can later be deployed using a Release Definition.

[caption id="attachment_9711" align="alignnone" width="204"] The build steps for an ASP.NET Core build in TFS/VSTS[/caption]

The problem here is that the artifacts that get published up is going to be missing all the dependent DLLs.  Exactly the same problem that I had on the command line.

To fix this problem in TFS/VSTS, you need to plug in the PublishWithAspNetCoreTargetManifest option into your build.

First, click on the Publish step.  Next, locate the Arguments field and add /property:PublishWithAspNetCoreTargetManifest=false to the end of that field.

[caption id="attachment_9712" align="alignnone" width="1024"] Add /property:PublishWithAspNetCoreTargetManifest=false to the dotnet publish step[/caption]

Now you can run your build and you'll get all the required files.

Summary

There's something odd in the way that the 'dotnet publish' command works with ASP.NET Core applications.  Whether it's by design or whether it's a bug, I'm not sure.  There are two workarounds: 1) Edit the project file (csproj) for your web project and add an msbuild property for  PublishWithAspNetCoreTargetManifest that's set to false or 2) supply the /property:PublishWithAspNetCoreTargetManifest=false to your dotnet publish commands.

I hope this helps.

-Ben

-- Has DevOps got you down?  Need help with your automated builds and releases?  Trying to figure out how to work DevOps thinking into your existing Agile/Scrum process?  We can help.  Drop us a line at info@benday.com.