loading...
Cover image for Creating a .NET Tool - Part 2: Packaging

Creating a .NET Tool - Part 2: Packaging

marcusturewicz profile image Marcus Turewicz ・4 min read

Creating a .NET Tool (3 Part Series)

1) Creating a .NET Tool - Part 1: Feeding the Dragon 2) Creating a .NET Tool - Part 2: Packaging 3) Creating a .NET Tool - Part 3: CI/CD

In Part 1 of this series, we created a command line program that can validate JSON files on disk, utilising System.CommandLine.DragonFruit for command line parsing and System.Text.Json for JSON validation. In this post, we'll add the necessary code to package the console app as a .NET Tool that can be published to NuGet. Let's jump right in!

Pack as tool

.NET Tools are by all accounts just regular NuGet packages, except they have special tags in their metadata. Given our app is already executable (we started with a console app), there's really only one line of code required to be added to the project file in order to transform the app into a .NET Tool:

<PackAsTool>true</PackAsTool>    

Once that line is added, you can package the tool with:

$ cd src/jsonv
$ dotnet pack

Which will create a NuGet package bin/Debug/jsonv.1.0.0.nupkg.

Then we can install the tool globally on our machine with:

$ dotnet tool install -g jsonv --add-source bin/Debug
You can invoke the tool using the following command: jsonv
Tool 'jsonv' (version '1.0.0') was successfully installed.

Then we can run the tool on our machine:

$ jsonv --file-path ../../global.json --allow-comments
File path is: ../../global.json, allowing comments: True
File is valid JSON!

Awesome, our tool can be installed and works like we expect.

By default, the command that invokes the tool, e.g. jsonv, is taken from the project file's name. If you would like a different name, you can add the following tag to the project file:

<ToolCommandName>my-very-cool-tool-name</ToolCommandName>

By default, the NuGet package is published to bin/[Configuration] path. If you would like a different path, you can add the following tag to the project file:

<PackageOutputPath>./my-very-cool-output-path</PackageOutputPath>

Great, we are now producing a tool that can be installed and invoked. Let's now add the appropriate metadata to allow this to be published to NuGet.org or a compatible NuGet server.

Package tool as a NuGet

There are tonnes of articles out there on creating NuGet packages, but I think the best is the Open-source library guidance. It covers all of the OSS library do's and don'ts. There is a specific section on NuGet that provides a nominal list of tags that every package should have. It's also recommended to add SourceLink which will add extra repoository related metadata to the package. Following that guidance, we end up with the following tags:

<PackageId>jsonv</PackageId>
<PackageVersion>1.0.0-alpha.1</PackageVersion>
<Description>A .NET Tool to validate JSON files on disk</Description>
<Authors>Marcus Turewicz, DEVCommunity</Authors>
<PackageTags>json json-validation json-validator</PackageTags>
<PackageIconUrl>https://github.com/marcusturewicz/jsonv/raw/master/logo.png</PackageIconUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>

And we should add the SourceLink package with:

<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> 

and add the tag to publish the repository URL with SourceLink:

<PublishRepositoryUrl>true</PublishRepositoryUrl>

Finally, our complete project file looks like:

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

  <PropertyGroup>
    <!-- Console app metadata -->
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <!-- Tool metadata -->
    <PackAsTool>true</PackAsTool>
     <!-- NuGet package metadata -->
    <PackageId>jsonv</PackageId>
    <PackageVersion>1.0.0-alpha.1</PackageVersion>
    <Description>A .NET Tool to validate JSON files on disk</Description>
    <Authors>Marcus Turewicz, DEVCommunity</Authors>
    <PackageTags>json json-validation json-validator</PackageTags>
    <PackageIconUrl>https://github.com/marcusturewicz/jsonv/raw/master/logo.png</PackageIconUrl>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <!-- SourceLink metadata -->
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.CommandLine.DragonFruit" Version="0.3.0-alpha.20214.1" />
    <!-- SourceLink package for GitHub -->
    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>    
  </ItemGroup>

</Project>

A few things to note

  • I have left out Title as I'm happy with the default being PackageId
  • I'm using SemVer2.0 for the PackageVersion
  • I've set the PackageProjectUrl as the GitHub repo url, but this could be the project website or docs site
  • This is guidance for OSS. If you're package is private source, then you should carefully consider which data you are providing and what will be public

Great, the tool is now ready for NuGet!

Summary

In this post, we added the necessary metadata to the project file to pack the console app as a .NET Tool and to publish the tool to NuGet. There are great guides provided by Microsoft that detail the steps to create quality OSS libraries and tools.

In the next post, we will setup a CI/CD pipeline that will build, pack and publish the tool to NuGet. Stay tuned!

Resources

Creating a .NET Tool (3 Part Series)

1) Creating a .NET Tool - Part 1: Feeding the Dragon 2) Creating a .NET Tool - Part 2: Packaging 3) Creating a .NET Tool - Part 3: CI/CD

Posted on Apr 1 by:

marcusturewicz profile

Marcus Turewicz

@marcusturewicz

Machine Learning Engineer, bassist, soccer player, .NET fan, native of the cloud and renewable energy advocate.

Discussion

markdown guide