0

The settings

My goal is to understand the CI/CD process on Azure (and in general). For that, I have build a little Wpf-App. It is not doing much. Just displaying a simple ReadMe.txt file.
A test project is included and the tests are running fine.
Also, I am practicing app-configuration by replacing placeholders in appsettings.json by varibles in azure-pipelines.yml. This is running as supposed.

The goal to accomplish

Now I am working on publishing a self-contained exe-file that is excluding appsettings.json. That is where I do need some help. Is this task configured, properly?

- task: DotNetCoreCLI@2
  displayName: 'Publish'
  inputs:
    command: publish
    publishWebProjects: false
    arguments: '-c $(buildConfiguration) -r $(runtimeId) --self-contained true --output $(build.artifactstagingdirectory)'
    zipAfterPublish: false
  enabled: true

References

enter image description here

The code

The project file:

  • the project's SelfContained property is set to true
  • the appsettings.json file ExcludeFromSingleFile property is set to true
  • the appsettings.[Environment].json files are added to gitignore.
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
    <SelfContained>True</SelfContained>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\DevOpsWpf.Library\DevOpsWpf.Library.csproj" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.Development.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <ExcludeFromSingleFile>True</ExcludeFromSingleFile>
    </None>
    <None Update="appsettings.Production.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.Staging.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Documentations\AzureDevOpsSolution.docx">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Documentations\ReadMe.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Properties\launchSettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
  
</Project>

The azure-pipeline file:

  • task VSBuild@1 is currently disabled
  • instead task DotNetCoreCLI@2 is enabled

I can not figure out which arguments in DotNetCoreCLI@2 to use to accomplish my goal.

trigger:
- main

pool:
  vmImage: 'windows-latest'

# Check replacetokens-task and appsettings.json
# the following variables are used in appsettings.json
# applicationHomeDirectory
# applicationName
variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  runtimeId: 'win-x64'
  buildConfiguration: 'Release'
  applicationHomeDirectory: 'C:\DevOpsSolution'
  applicationName: 'Azur DevOps Solution (azure-pipelines.yml)'

# not sure, if this is needed
steps:
- task: DeleteFiles@1
  displayName: 'Delete files in artifactstagingdirectory'
  inputs:
    SourceFolder: '$(build.artifactstagingdirectory)'
    Contents: '**'

# working as intended
- task: NuGetToolInstaller@1
  displayName: 'Use NuGet 6.8.0'

# working as intended
- task: NuGetCommand@2
  displayName: 'Restore NuGet Packages'
  inputs:
    restoreSolution: '$(solution)'

# working as intended
- task: qetza.replacetokens.replacetokens-task.replacetokens@5
  displayName: 'Replace tokens in appsettings.json'
  inputs:
    targetFiles: '**/*.json'

# disabled task for testing
- task: VSBuild@1
  displayName: 'Build solution'
  inputs:
    solution: '$(solution)'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'
  enabled: false
    
# testing this task instead of VSBuild; in artifact there are tons of files, instead of one exe-file and one json-file
- task: DotNetCoreCLI@2
  displayName: 'Publish'
  inputs:
    command: publish
    publishWebProjects: false
    arguments: '-c $(buildConfiguration) -r $(runtimeId) --self-contained true --output $(build.artifactstagingdirectory)'
    zipAfterPublish: false
  enabled: true

# working as intended
- task: VSTest@2
  displayName: 'Test solution'
  inputs:
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

# working to publish it to SolutionDrop; not sure if this is all that needs to be done here
- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: SolutionDrop'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
    ArtifactName: SolutionDrop
  condition: succeededOrFailed()

The published artifact is >200 MB and has a ton of files. That can not be correct. Here you see just the top: enter image description here

1 Answer 1

0

Finally, I have received the result as it was intended to be.

This answer was the final clue. And I did find the reference in Microsoft documentation.

enter image description here

These properties are set in the project file:

    <PublishSingleFile>true</PublishSingleFile>
    <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>

There was a change in the publish process by Microsoft. If PublishSingleFile is set to true, Self-Contained is implied automatically.
When the above properties are set in the project file, they do not need to be listed as arguments in the command line.

The DotNetCoreCLI@2 task looks like this:

steps:
- task: DotNetCoreCLI@2
  displayName: 'Publish *.csproj'
  inputs:
    command: publish
    publishWebProjects: false
    projects: '**/DevOpsWpf.csproj'
    arguments: '-c Release -r win-x64 --output $(build.artifactstagingdirectory)'
    zipAfterPublish: false

The project file looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
    <PublishSingleFile>true</PublishSingleFile>
    <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\DevOpsWpf.Library\DevOpsWpf.Library.csproj" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.Development.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <ExcludeFromSingleFile>True</ExcludeFromSingleFile>
    </None>
    <None Update="appsettings.Production.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Documentations\ReadMe.txt">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Properties\launchSettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
  
</Project>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.