sdk: dotnet publish does not copy the documentation file with csproj

Steps to reproduce

Have a solution with multiple projects The main “web” project has the GenerateDocumentationFile set to true

Expected behavior

When I run dotnet publish of the main “web” project, I expect that the XML documentation file is copied into the publishing folder. (Note the build will generate the file as it should.)

Actual behavior

When I run dotnet publish of the main “web” project, it does not copy the XML documentation file to the psublish folder.

My workaround

My current workaround is to update the csproj of the main web project and manually copy the file:

<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
		<ItemGroup>
			<DocFile Include="bin\**\**\PROJECT_XYZ.xml" />
		</ItemGroup>
		<Copy SourceFiles="@(DocFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false"  />
  </Target>

Environment data

.NET Command Line Tools (1.0.0-rc3-004530)

Product Information: Version: 1.0.0-rc3-004530 Commit SHA-1 hash: 0de3338607

Runtime Environment: OS Name: Windows OS Version: 6.3.9600 OS Platform: Windows RID: win81-x64 Base Path: C:\Program Files\dotnet\sdk\1.0.0-rc3-004530

This issue has been copied over from https://github.com/dotnet/cli/issues/5562.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 27
  • Comments: 54 (27 by maintainers)

Commits related to this issue

Most upvoted comments

Hello @davkean , My project is a big WebAPI netcore and like many API, I’m using Swagger whom needs the XML documentation file if I want to have a good documentation for my API. Also, it use to work when I was using .xproj.

Also, another of my project (solution with multiple projects) has the flag GenerateDocumentationFile turned On and somehow that one is copied over.

So in a nutshell, it use to work and now I see two different things contradicting themselves.

thank you, JS

@masterjs What’s the expectation around this? Why do you expect the XML file to be published - it’s a dev artefact.

this highlights the main advantage of moving from project.json to MSBuild

+1. MSBuild extensibility is awesome.

But back to the main point of this issue. Should the SDK include xml docs in the published output by default?

My vote: yes.

This Target will work on all platforms and in web and console apps:

  <Target Name="CopyDocumentationFile"
          AfterTargets="ComputeFilesToPublish">
    <ItemGroup>
      <ResolvedFileToPublish Include="@(FinalDocFile)"
                             RelativePath="@(FinalDocFile->'%(Filename)%(Extension)')" />
    </ItemGroup>
  </Target>

ResolvedFileToPublish is the Item that publish uses to know which files to put in the publish folder. The Include is the file’s source, and the RelativePath is where inside the publish folder the file should be placed. ComputeFilesToPublish is exactly as its name implies - it is the Target that gathers all the files to be published.

@spboyer, cc @GuardRex: another workaround would be to use the $(DocumentationFile) property to emit items that are respected during publish like this:

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<Target Name="IncludeDocFile" BeforeTargets="PrepareForPublish">
  <ItemGroup Condition=" '$(DocumentationFile)' != '' ">
    <_DocumentationFile Include="$(DocumentationFile)" />
    <ContentWithTargetPath Include="@(_DocumentationFile->'%(FullPath)')"
                           RelativePath="%(_DocumentationFile.Identity)"
                           TargetPath="%(_DocumentationFile.Filename)%(_DocumentationFile.Extension)"
                           CopyToPublishDirectory="PreserveNewest" />
  </ItemGroup>
</Target>

If more files are needed, more _DocumentationFile items using a pattern could be used.

@pgmolloy does anything not work in your publish scenario? This has been implemented.

For those having trouble getting DocumentationFile to work, I recommend deleting it and letting MSBuild autogenerate a correct path by setting GenerateDocumentationFile instead:

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

For my case, since It’s for a web api I only care about the generated documentation. I dont mind and understand if it needs a little bit more work like I did for my work-around. The main problem was that it was a different behavior from xproj when I migrated to csproj and the documentation file of other projects was still copied.

For those having issues with this and service fabric, there is a slight tweak to the .csproj change you need to make to get it to work:

<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish"> <ItemGroup> <DocFile Include="bin\x64\$(Configuration)\$(TargetFramework)\win7-x64\*.xml" /> </ItemGroup> <Copy SourceFiles="@(DocFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" /> </Target>

Also remember that sometimes the property group is not completely changed by Visual Studio. Ensure the below lines are present:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <DocumentationFile>bin\Debug\net462\win7-x64\WebApiSwagger.XML</DocumentationFile> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <DocumentationFile>bin\Debug\net462\win7-x64\WebApiSwagger.XML</DocumentationFile> </PropertyGroup> I have verified this works.

In Visual Studio, we should have the option either in the Properties of the project where you enable the xml documentation file and/or right click action to include the file in the output or publish location which then creates the entry in .csproj like @dasMulli put above.

For non-VS users, documentation noting how to do this or simplifying the entry in .csproj via a flag maybe a good/better solution.

Proposed : requires change to tooling

<PropertyGroup>
  <GenerateDocumentationFile
        CopyToPublishDirectory="PreserveNewest" 
        Option="true" />
</PropertyGroup>

cc:/ @sayedihashimi

You can modify the csproj file to add the necessary files to pipeline that MSBuild needs to package up for the publish process. To add the Swagger files add the following snippet to the end of you *.csproj file before </Project>

  <Target Name="SwaggerFile">
    <ItemGroup>
      <_CustomFiles Include="bin\(Configuration)\(Platform)\*.xml" />
      <FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
        <DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
      </FilesForPackagingFromProject>
    </ItemGroup>
  </Target>

  <PropertyGroup>
      <CopyAllFilesToSingleFolderForPackageDependsOn>
        SwaggerFile;
        $(CopyAllFilesToSingleFolderForPackageDependsOn);
      </CopyAllFilesToSingleFolderForPackageDependsOn>
  </PropertyGroup>

This copies the documentation file to the root of the project prior to the MSBUILD process running . dotnet publish will place the file in whatever output location you specify and configuration.

cc:/ @sayedihashimi

What about if you want to include documentation files for other package referenced assemblies. My scenario is that I have moved a shared controller to a NuGet package and want to include it’s documentation file in my Swagger page.

I’d like to see a more built-in solution like building SDK support for:

<PropertyGroup>
  <PublishDocumentationFile>true</PublishDocumentationFile>
  <!-- Next one is a nice to have -->
  <PublishDependencyDocumentationFiles>true</PublishDependencyDocumentationFiles>
</PropertyGroup>

This would be easy for tooling (=> checkbox) and hand-editing csproj files. Defaults could also be set easily via the SDK, WebSDK or NuGet packages (Swashbuckle).

Documentation files are what Swashbuckle can use at runtime to enrich the generated Swagger API description. It’s nice for Web API projects because you just need to write a documentation once that works for IntelliSense, doc generation tools AND runtime Swagger generation, making it more than just a dev artifact. So it does make sense to publish it with the application in some scenarios.

@eerhardt has the best option. Created sample project for ref https://github.com/spboyer/copydocfile-example

This works for me. Verified on Windows, macOS and Ubuntu

<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
    <ItemGroup>
      <DocFile Include="bin\$(Configuration)\$(TargetFramework)\*.xml" />
    </ItemGroup>
    <Copy SourceFiles="@(DocFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
  </Target>

using xml comments for swagger is already documented on docs.microsoft.com by @spboyer so maybe the doc would need to be updated that this won’t work with the 1.0 tooling when published?

you can change the existing condition:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU' OR '$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DocumentationFile>ProjectName.xml</DocumentationFile>
  </PropertyGroup>

this worked for me with swagger in NetCore 3.1 ` <PropertyGroup>

<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PublishDocumentationFile>true</PublishDocumentationFile>
<DocumentationFile>$(MSBuildThisFileDirectory)\bin\$(Configuration)\$(TargetFramework)\AnyFile.xml</DocumentationFile>
</PropertyGroup> `

It is a MSBuild property that you can set in your csproj.

<GenerateDocumentationFile>true</GenerateDocumentationFile>

Realised that I was calling msbuild with Release configuration (the same way the build agents were). I solved my problem by simply including the DocumentationFile in my project.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <!-- ... -->
  <DocumentationFile>bin\Api.XML</DocumentationFile>
</PropertyGroup>

I would like to vote for adding the swagger xml file to the build. My opinion is that the swagger xml file is NOT a doc file but a “necessary component” similar to a web config or an app settings file required by my Azure API to run. When deploying to Azure, my API will not start without the file. Just two cents worth 😃

I found the file was being created on my desktop from VS2017 in the ‘Release’ Configuration but was not being created in VSTS on release configuration

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <DocumentationFile>bin\Debug\netcoreapp1.1\Host.xml</DocumentationFile> </PropertyGroup>

I wondered if perhaps the ‘AnyCPU’ Platform was not being applied in VSTS so I removed that part from my csproj file and it built properly including my documentation file in VSTS in ‘Release’ so I guess AnyCPU is not the right platform setting or default platform setting in VSTS

<PropertyGroup Condition="'$(Configuration)'=='Release'"> <DocumentationFile>bin\Release\netcoreapp1.1\Host.xml</DocumentationFile> </PropertyGroup>

Why is this closed?

I don’t get why we have to add extra Targets and hack around something that should be natively supported or at least be a configurable option.

XML Comments are no longer a development artifact with the rise of Swagger for example. To produced self documenting swagger documentation at runtime all the XML comments must be included in the application.

What is the rationale for not copying XML documentation? The documentation is already included in the nuget package on a build or publish?

Hi guys,

Been working on a project where i am required to include xml documentation. This works as expected, when adding the GenerateDocumentationFile tag.

The problem is, that I need to be able to include the xml documentation of packages that come from nuget. I see this question was asked before, but did not see it get addressed.

How would one go around this?

My use case is specifically for swagger / swashbuckle. We have common projects, which have extensive documentation, we would like to have this included.

Thanks

I thought I had hit this issue as well.

My issue was that I had the xml documentation file only setup to generate in Debug Build.

Make sure you don’t have a condition in your .csproj file to only look at Debug Builds.

That’s our version, which works on Linux, Windows and Mac - similar what @eerhardt provided.

In the main section, ensure the documentation file gets generated:

  <GenerateDocumentationFile>true</GenerateDocumentationFile>

Then a separate target with the copy process:

  <Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
    <ItemGroup>
      <DocFile Include="bin\*\*\MyProject.xml" />
    </ItemGroup>
    <Copy SourceFiles="@(DocFile)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
  </Target>

The swagger doc has been updated in the csproj branch, will be pushing that to live when RTM is released approx Mar 7

@louislewis2 This is being tracked in #1458. This comment specifically has links to workarounds you can apply. Thanks!