If, like me, you sometimes develop internal tools for your team of developers,you may be interested in learning how to create a dotnet tool package “manually”.

This article explains how to do this step by step.

Of course, for Console projects, you can add the <PackAsTool> and <ToolCommandName> parameters to your csproj. But for a website, you need a whole series of files that are only generated during publication.

1. Create your website

First, you need to have a website. You can quickly create one using dotnet new blazorserver.

Later, we will publish this website using dotnet publish -c Release -o ./bin/Publish so that the website will be available in a subfolder called bin/publish.

2. Set up your project

You must add these two files to configure your project as a DotNet Tool package.

  • Add this DotnetTool.nuspec file to the root of your project. Adapt the id with the name of your tool (as well as the dotnet version number net9.0 you are using).

    <package>
      <metadata>
        <id>my-tool</id>
        <version>1.0.0</version>
        <authors>Denis Voituron</authors>
        <owners>Denis Voituron</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>
          Add your description here.
        </description>
        <tags>tool</tags>
        <packageTypes>
          <packageType name="DotnetTool" />
        </packageTypes>
      </metadata>
      <files>
        <file src="bin\publish\**\*.*" target="tools\net9.0\any" />
        <file src="DotnetToolSettings.xml" target="tools\net9.0\any\DotnetToolSettings.xml" />
      </files>
    </package>
    
  • Also add this DotnetToolSettings.xml file to the root of your project. This file specifies which entry point (DLL or EXE) to start when the my-tool command is typed.

    <?xml version="1.0" encoding="utf-8"?>
    <DotNetCliTool Version="1">
      <Commands>
        <Command Name="my-tool" EntryPoint="MyApplication1.dll" Runner="dotnet" />
      </Commands>
    </DotNetCliTool>
    

3. Adapt your Program.cs

By default, your project should start with port 5000 with an Assets folder wwwroot referenced from the current folder. You can adapt this via this part of code to be placed in your Program class.

You can also automatically start the default browser to immediately display your website.

public class Program
{
	public static void Main(string[] args)
	{
#if (RELEASE)
		var wwwRootDirectory = Path.Combine(AppContext.BaseDirectory, "wwwroot");
		var options = new WebApplicationOptions
		{
			WebRootPath = wwwRootDirectory,
			Args = args,
		};

		var builder = WebApplication.CreateBuilder(options);

		builder.WebHost.ConfigureKestrel(serverOptions =>
		{
			serverOptions.ListenAnyIP(6789, listenOptions =>  // 👈 Set a specific port number
			{
            // Uses the trusted dev cert automatically
				listenOptions.UseHttps(); 
			});
		});
#else
		var builder = WebApplication.CreateBuilder(args);
#endif

		// Keep the existing code
      // ...

		var app = builder.Build();

		// Keep the existing code
      // ...

		// Launch browser only in release mode and when running locally
#if RELEASE
		if (OperatingSystem.IsWindows() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
		{
			var url = "https://localhost:6789"; // or your configured URL
                try
			{
				System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
				{
					FileName = url,
					UseShellExecute = true
				});
			}
			catch (Exception ex)
			{
				Console.WriteLine($"Failed to launch browser: {ex.Message}");
			}
		}
#endif

		app.Run();
	}
}

4. Create the DotNet Tool package

  • Open a console in your project folder and run the publish command.
    dotnet publish -c Release -o ./bin/Publish
    

    You can also delete the ‘bin’ and ‘obj’ folders before compiling to ensure a clean compilation.

  • Next, run this NuGet command, to create the nupkg package.

    nuget pack DotnetTool.nuspec -OutputDirectory ./bin/
    

    The file MyApplication1.x.x.x.nupkg will be generated in the bin subfolder. All you have to do now is push it to an internal NuGet feed within your company or to NuGet.org if it is public.

5. Install the tool before publishing it

  • Run the following command to install a self-signed “https://localhost” development certificate (silent installation).
    dotnet dev-certs https --trust
    
  • Install the tool locally using this command.
    dotnet tool install --global --add-source ./bin my-tool
    

    The parameter --add-source ./bin specifies the location of the package to be installed.

  • Test your new command, which should start a website and open the browser.
    my-tool