Starting with .NET Core 2.1, Microsoft introduced the .NET Core Tools platform as part of the .NET Core SDK and since then, these tools have become a vital, although underutilized part of the .NET ecosystem. .NET Core Tools are a simple way to create, publish, and consume what are essentially .NET Core applications that can be published and shared using the existing NuGet infrastructure for packaging and distribution. This means it's quick and easy to build tools that you can share either publicly with the world or privately with yourself or your onsite team.

What's a .NET Core Tool?

When you break down a .NET Core Tool into its simplest terms, you end up with this simple statement:

A .NET Core Tool is a glorified .NET Core application that can be quickly and easily shared and installed via NuGet.

The idea behind a .NET Core Tool is to make it easy to build, publish, and consume executable tools in the same way you can create NuGet packages for .NET and .NET Core components.

Although the original idea was to build tools to aid as part of the build and development process, this platform really offers a much wider scope because you can publish and share any .NET Core executable application. This includes servers that run full ASP.NET Core applications or services and even .NET Core desktop applications.

Why Use Dotnet Tools?

Although the idea behind .NET Core Tools isn't anything new, this tooling does provide several benefits to developers and the entire .NET Core ecosystem. The big selling points are:

  • Easy to use
  • Single command installs. Example: dotnet tool install -g LiveReloadServer
  • Global path access to run command: LiveReloadServer –help
  • Easy to build
  • Uses standard .NET Core projects
  • Uses existing NuGet infrastructure
  • Nothing new to learn - works with existing tech
  • Configured via standard .csproj settings
  • Sharing
  • Can be easily shared
  • Can reach a large number of users via NuGet
  • Quickly published and available
  • No explicit package validation
  • Community
  • Ease of use and shareability promotes creation of tools
  • Shared content helps build community

On the flip side, there's a big prerequisite to using a .NET Core Tool:

  • The .NET Core SDK is required to install a .NET Core Tool

The SDK dependence is both a blessing and a curse: Because the .NET Core Runtime is guaranteed to be installed, binaries of your .NET Core Tool can be very small and only consist of application-specific files. But the .NET SDK must exist on the target computer and this SDK install is neither small, nor something that a typical, non-development user already has installed.

Global and Local .NET Core Tools

.NET Core Tools can be installed either as a global or local tool. Global tools are installed in a central location on the local computer and mapped on the global path, so they are globally accessible. Local tools are installed into a specific folder and only accessible from there. They're essentially project-specific and they-re useful for build systems that need to encapsulate tools as part of a build process or Continuous Integration (CI).

In this article, I focus on the usage for global tools and the sharing aspects of .NET Core Tools as general-purpose utilities using the global -g command line switch. Everything except the install location and global path access also applies to local tools in the examples.

Careful: Security of .NET Core Tools

Because .NET Cire Tools are executables installed from a remote source and because there's no validation process for published tools, it's important to understand that there is a potential security risk to your computer. The code that comes down can execute locally on your system and has access to your local resources when you run the tool.

Be sure you:

  • Trust the publisher of the tool.
  • Verify that the tool has reviewable source code available in a repository.
  • Check for issues on the repository.

Be careful and know the risks!

To be fair, the same cautions apply to NuGet packages because those too can execute any code contained in the package or in a constructor and there's not much concern around that.

.NET Core Tools install and run on your local computer, but they're not validated in the NuGet Package Store, so there's a potential security risk.

There's Nothing New Under the Sun!

"Did you just describe NPM?"

Yup: .NET Core Tools are very much like NPM for .NET Core.

If all this looks familiar from Node,js and NPM - you're right. The idea of shared tools isn't new by any means and follows various other development platforms and their package managers. But for .NET to easily publish and share binary executable tools in a cross-platform manner is relatively new and opens up the reach of small and useful tools that otherwise would never be shared.

What Can You Use .NET Core Tools For?

Although .NET Core Tools were initially designed to provide development time helper tools, they're just plain .NET Core executables that can do anything that a .NET Core executable can do. This means you can use it for all sorts of things that might not be directly developer related.

Here are a few general use cases addressed by .NET Core Tools:

  • Build and Development Tools: There are many tools that follow the original design goal for creating project helpers that make development tasks easier or facilitate external but related development operations. For example, tools like EF migration commands in dotnet ef, dotnet watch run, the user secrets manager and dotnet watch are all .NET Core Tools that fit this bill. There are many tools available in this category.
  • Generic Command Line Tools: If you need to build some complex command line helpers that work on scenarios that are more complex than what you reasonably want to do in PowerShell or Bash, a tool can fit that niche nicely. Because these tools can be shared and installed easily and are generally very small, they make a good fit for beyond scripting scenarios.
  • Local Servers: .NET Core makes it easy to build server applications and it's easy to create self-contained Web Server or Services applications. Whether it's running a Web application locally for testing, or whether you have some internal application that maybe is a hybrid using both a Web interface and a desktop application in mixed mode, a .NET Core Tool makes it easy to provide this. It's very powerful to be able to create small and easily shareable, self-contained Web and server applications. I'll show a couple of examples of this later.
  • Desktop Applications: Although Microsoft's official documentation claims that .NET Core Tool is meant for console applications, it turns out that you can also create .NET Core WinForms and WPF applications and package them as tools too. But they are Windows-only.

Locating Available .NET Core Tools

One of the reasons that .NET Core Tools aren't so widely used that it's not that easy to find them. Until very recently, you weren't even able to search the NuGet Site specifically for tools but that was recently fixed with new search filters.

There are a couple of other places you can check for tools:

.NET Core Tool or Platform-Specific Binary?

.NET Core supports creating executable binaries for every platform that it supports. But each platform requires a custom executable launcher and runtime dependencies to run. It takes quite a bit of extra effort to create these separate build targets and distribute each one.

It's possible to create standalone executables for each platform using either a pre-installed .NET Core runtime installation or a fully self-contained executable that can contain all the required runtime files in addition to the files that your application needs to run. Self-contained applications are great for self-reliance and predictable behavior, but they're terribly large, as the .NET Core base runtimes make up a minimum of 70MB of distribution size.

A fully self-contained application is useful and sometimes required. If you're building an end user tool or application, a self-contained application that has everything it needs included is usually a better call. But if you're building developer tools, the lightweight and universal .NET Core Tool distribution experience is often preferable.

The advantage of building a .NET Core Tool is that it's not platform-specific. Like a NuGet component, a .NET Core Tool is distributed as a NuGet package that contains only the compiled .NET assemblies. There's no launching executable packaged. Because .NET Core Tools rely on an SDK installation to run, the runtime is guaranteed to be there. If dotnet tool can run on the computer, so can your .NET Core Tool.

This means that you can build a single, relatively small NuGet package as a .NET Core Tool and it will work on all supported .NET Core platforms, assuming your code is written to otherwise use platform-agnostic features. That's cool: The .NET Core Tool provides you with cross-platform functionality without having to build and maintain multiple platform-specific loaders and it keeps the deployment size very small.

Creating and Using .NET Core Tools

Enough abstract talk! Let's jump in and see how you can:

  • Build a .NET Core Tool package for distribution
  • Publish a .NET Core Tool package
  • Consume a .NET Core Tool package

Create a .NET Core Tool Step-by-Step

Let's create a very simple project called MagicWindBall that predicts wind conditions for the day. It's a play on the words of Magic Eightball, which is a fake fortune telling device and I'm hijacking the idea to tell me my wind fortunes.

Start by creating a .NET Core Console project. I'll use the dotnet command line tooling, but you can also use Visual Studio (or Rider, etc.) to create a new .NET Core Console project.

From the command line, start by creating a new folder with the Project name, and then create a project in that folder:

mkdir MagicWindBallcd MagicWindBalldotnet new consolecode .

This creates a new project MagicWindBall.csproj that you can open in Visual Studio or Visual Studio Code. I'll use VS Code here, as shown in Figure 1, which makes it easy to open the projects from a folder via the ``code .` command.

This project is very simple, with an imaginary wind forecast generator that randomly displays a string from a list of pre-defined wind condition strings.

The code is along the lines of Listing 1 (full code on GitHub at https://tinyurl.com/MagicWindBall).

Listing 1: The MagicWindBall Sample Tool

static void Main(string[] args)
{
    WriteWrappedHeader("Magic WindBall");
    Console.WriteLine();
    Write("thinking.", ConsoleColor.Cyan);    
    Wait(500);
    Write(" consulting the stars.", ConsoleColor.Yellow);    
    Wait(1000);    
    Write(".", ConsoleColor.Yellow);
    Write(" guessing some more.", ConsoleColor.Cyan);
    Wait(1000);
    Write(".", ConsoleColor.Cyan);
    Console.WriteLine('\n');
    
    var rnd = new Random(DateTime.UtcNow.Millisecond);
    var val = rnd.Next(6);
    Console.WriteLine("Wind today be:");
    
    switch (val)
    {
        case 0:
            WriteLine("No Wind - Skunked again.", ConsoleColor.DarkYellow);
            break;
        case 1:
            WriteLine("Light Wind - Pray for wind.", ConsoleColor.DarkCyan);
            break;
        case 2:
            WriteLine("Light Breeze - Sucker wind.", ConsoleColor.DarkGreen);
            break;
        case 3:
            WriteLine("Breezy- Wake up and get ready.", ConsoleColor.Green);
            break;
        case 4:
            WriteLine("Windy- Why are you still here?", ConsoleColor.Yellow);
            break;
        case 5:
            WriteLine("Super Nuker? Batten down the hatches", ConsoleColor.Red);
            break;
        default:
            WriteLine("Roll the Dice- Coming in waves.");
            break;
    }
    
    Console.WriteLine();
}

First, let's make sure the code works as a regular Console application. Open a Terminal in the project folder and do:

dotnet run

In Figure 1, I use the built-in Terminal in VS Code to test the application.

.NET Core Tools use the existing .NET tool infrastructure for creation, publishing, and installing tools.

Make It a .NET Core Tool

You now have a plain .NET Core Console application. To turn this into a .NET Core Tool, add a few specific settings to the project file. At minimum, you need to add a few .NET Core Tool-specific settings to the project. Add <PackAsTool>, provide a name, and set up the project to build as a NuGet package, as shown in Listing 2.

Listing 2: Adding Dotnet Tool specific .csproj settings

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
  
  <!-- Dotnet Tool Specific settings -->
  <PropertyGroup>
    <PackAsTool>true</PackAsTool>
    <PackageId>dotnet-magicwindball</PackageId>
    <ToolCommandName>magicwindball</ToolCommandName>
    <PackageOutputPath>./nupkg</PackageOutputPath>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>
</Project>

With these flags in place, you can now build the project and generate the .NET Core Tool NuGet Package into the ./nupkg folder:

dotnet build -c Release

If you use Visual Studio, just build in Release mode.

This builds the project and creates a NuGet Package in the ./nupkg folder. You can use the NuGet Package Explorer to spy into the package to see what's in the package, as shown in Figure 2.

Testing the .NET Core Tool Locally

Once you've created the NuGet Package, you'll probably want to test it locally first before publishing it. You can do that by installing the .NET Core Tool locally from a folder. To install, you use dotnet tool install or dotnet tool update.

For public tools that come from the default cloud based NuGet package store, you use:

dotnet tool install =g dotnet-magicwindball

But...it doesn't work yet because I haven't published the package yet. You can test the package locally by installing the NuGet component from a folder by specifying the --add-source ./nupkg command line option:

dotnet tool install -g dotnet-magicwindball add-source ./nupkg

Et voila! You've just installed the .NET Core Tool locally and you can now run the tool simply by typing magicwindball into the Terminal from anywhere on your computer. Figure 3 shows building, installing, and running the tool in a Terminal window.

Figure 3: Build and run your .NET Core Tool locally
Figure 3: Build and run your .NET Core Tool locally

Publishing to NuGet

.NET Core Tools are published as NuGet packages and use the same exact mechanism you use to publish a NuGet package for a .NET Component. You use NuGet publish or you can also use the NuGet Package Explorer shown earlier in Figure 2.

Here's a build, sign, and publish PowerShell script (the full script is here: https://tinyurl.com/SnippetConverter):

dotnet build -c Release

$filename = gci "./nupkg/*.nupkg" | `
                sort LastWriteTime | `
                select -last 1 | `
                select -ExpandProperty "Name"
$len = $filename.length

if ($len -gt 0) {
    nuget sign  ".\nupkg\$filename"   `
          -CertificateSubject "West Wind " `
          -timestamper "..."
    nuget push  ".\nupkg\$filename"
          -source nuget.org}

Note that NuGet Package signing is optional, but because I already have a publisher certificate, I'm using it to sign my package. For the nuget push to work, you'll need to set the active NuGet publishing ID before you publish the package.

nuget setApiKey <your_API_key>

Figure 4 shows what the published package looks like on the NuGet Package Store site.

Once published, the package becomes accessible within a few minutes. Feed listings can take a bit longer, so you may have to explicitly specify a version on the command line using the --version flag.

You can now install and run the component from the NuGet Package Store. Figure 5 shows the install and run sequence.

Figure 5: Install and run a .NET Core Tool
Figure 5: Install and run a .NET Core Tool

If you need to update the .NET Core Tool, make your code changes and increment the version number of the project then simply re-publish to NuGet. A new package with the new version number is created and pushed, which then becomes available on NuGet. You can then use dotnet tool update -g dotnet-magicwindball to update the local tool installation to the updated version.

How a Tool Gets Executed

.NET Core Tools are deployed as .NET NuGet packages that don't include an OS specific executable file. Rather, when a tool is installed, a platform-specific, native launcher executable is generated that acts as a proxy launcher for the .NET Core runtime, which then bootstraps the .NET Core Tool entry assembly. The launcher is created in a system mapped .dotnet folder and is then globally available using the <CommandName> specified by the project. Figure 6 shows the launcher in the .dotnet root folder and the actual install folder that holds only the .NET assemblies that execute on any platform.

Figure 6: An installed .NET Core Tool uses a proxy executable to launch the .NET Core Tool.
Figure 6: An installed .NET Core Tool uses a proxy executable to launch the .NET Core Tool.

The .dotnet/.store path holds the actual unpacked NuGet package content for each tool installed. When you run the launcher (magicwindball.exe on Windows), it loads the .NET Core runtime and then calls the static void Main() entry point in the entry assembly of the package. The .exe you see on the left in Figure 6 is only a stub launcher. If you hook up an IL decompiler to the EXE as I've done in Figure 6 with Reflector, you'll find that the exe is a native binary, not a .NET assembly.

.NET Core Tools create a platform-specific executable launched in a globally accessible folder to make the tool available globally from anywhere on the computer.

Running on Another Platform: Linux with WSL and Mac

.NET Core Tools are platform agnostic and, assuming your application doesn't use any platform-specific features, they can run on Windows, Mac, or Linux from a single distribution.

So, let's run this .NET Core Tool on Linux using Windows Subsystem for Linux (WSL) using the same steps as before. Use dotnet tool install and then execute the command. Figure 7 shows what that looks like inside of WSL. You can do the same on an actual Linux or Mac computer. Figure 8 shows running on a Mac.

It all works on all .NET Core supported platforms from the single .NET Core Tool package, as long as your code doesn't do anything platform-specific.

.NET Core Tools don't need platform-specific builds: They run on any supported .NET Core platform from a single code base and NuGet package.

Listing and Managing Installed Tools

You can check what tools you have installed by using the dotnet tool list -g command, as shown in Figure 9.

The list shows both the Package Id, which is the install name used with NuGet, and the Command name, which is used to run the package. Package ID and Command can be different, as demonstrated by the dotnet-magicwindball ID and the magicwindball command. But they don't have to be different. For example, my LiveReloadServer package uses the same name for the package ID and command name. The dotnet- prefix is an original convention used by various .NET internal tools to make it obvious that they're .NET tools, but that convention is discouraged now. Generally, it's better to use the same name for the package ID and command and to use the most descriptive name possible.

Keep in mind that tool command names are case sensitive on case sensitive operating systems.

You can keep tools up to date using the update command:

dotnet tool update -g dotnet-magicwindball

The update command also installs a tool if it isn't already installed. You can also easily uninstall tools with uninstall:

dotnet tool uninstall -g dotnet-magicwindball

Example Components

To bring home the utility of .NET Core Tools, I'd like to describe a few of the .NET Core Tools I've created and discuss the hows and whys of creating them. I've been huge fan of these tools because it's so frictionless to publish a tool for easy reuse. If it weren't for the ease of sharing via NuGet, I probably wouldn't have bothered sharing these tools at all.

Some of these tools I built mainly for myself, but because I've made them public, they ended up getting used by quite a few other people. Maybe you'll find some of these useful as well. But more importantly, I hope it inspires you to share your own tools no matter how silly or simple - somebody else might find them useful too!

Simple Tools

The first couple of examples are your typical utility tools that, under normal circumstances, I would have distributed as a downloadable installer or just a standalone binary. If a tool is popular enough, I still go that route in addition to the .NET Core Tool, but I tend to use the .NET Core Tool rather than a standalone installed application.

Visual Studio Snippet Converter

This tool (https://tinyurl.com/SnippetConverter) is a small utility to convert Visual Studio Code Snippets (code expansions) to other development environments. It supports:

  • Visual Studio Code Snippets
  • JetBrains Rider Snippets

This tool is directly targeted at developers who are already using Visual Studio and so are very likely to have the .NET SDK installed just by virtue of using Visual Studio. As a tool, this is perfect, and it fits the .NET Core Project Tooling use case that was the original design goal by Microsoft.

The background behind this tool is that I have a ton of Visual Studio code snippets that help me quickly format blocks of code - from inserting properties, creating entire blocks of classes that have complex signatures or inserting complex HTML markup completions for various Web frameworks. Snippets are an incredibly useful and very underutilized feature in various IDEs.

I use several different development tools: Visual Studio, VS Code, and Rider, and sharing snippets across them is much easier than recreating them in each environment.

This tool lets me export my Visual Studio snippets into VS Code and Rider. It also provides me use a “master” snippet repository in Visual Studio that allows me to update snippets there and then easily update the snippets in the other environments with the .NET Core Tool.

To use this tool:

dotnet Tool install -g snippetconverter

For options, just run it and it shows the options shown in Figure 10, which illustrates the functionality best.

To run the converter, you can specify a source snippet or folder and an output path:

snippetconverter `
    "~\Visual C#\My Code Snippets" `
    -o "~\ww-csharp.code-snippets" `
    -m vs-vscode -r -d

To make the snippet location easier to use, the tool lets you use ~ for the default snippet folders for each IDE. For Visual Studio, this points to the <Documents>\Visual Studio 2019 Code Snippets folder, for example.

Figure 11 shows the source snippet folder and output generated by the Visual Studio code export:

HtmlPackager

HtmlPackager (https://tinyurl.com/HtmlPackager) is a tool to package an HTML URL into a fully self-contained package or folder, bringing all the content offline so it can be viewed completely offline. It's similar to Save as... in a Web browser, but you can automate the process. This is useful for attaching to emails or for archival purposes.

This tool came about because I needed this functionality at the time for my Markdown Monster (https://markdonwmonster.west-wind.com) editor. I looked around for a command line tool but came up with nothing that worked that had a small footprint and no dependencies. As a result, I ended up building a .NET library that I used in Markdown Monster initially, but then also built into a .NET Core Tool so it can be used from the command line and automated.

It's a general-purpose tool and .NET Core Tooling provides a very easy way to publish and share it.

The dotnet-htmlpackager tool can be installed with:

dotnet tool install -g dotnet-htmlpackager

Once installed, you can run it using the help command to see the command line options. To capture a URL, it uses a command like this:

htmlpackager  https://west-wind.com `  -v -o /temp/captured/MarkdownMonster.html

This creates a single very large but fully self-contained HTML file as shown in Figure 12.

There are other options for creating:

  • A folder of loose HTML and resource files (-x)
  • A zip file of the folder of loose HTML and resources (-z)

Servers

A .NET Core Tool is just a .NET Core application, so you can take advantage of just about any .NET Core feature, including the ability to create self-contained Web server applications and services that you can run locally.

LiveReloadServer: A Generic Static File Web Server

I frequently run local static websites on my development computer for quickly running a SPA application, working on static website content or one of my many standalone JavaScript library projects.

I could spin up a full development environment like Visual Studio and IIS Express, or use something like WebPack to provide infrastructure for hosting and running, but that but that feels like overkill for many of the simple run and edit scenarios I have. As an alternative, using the LiveReloadServer (https://tinyurl.com/LiveReloadServer), I can quickly run a local development server and just run a local folder as a website. It's a small, self-contained .NET Core-based static Web Server that can serve local static file content out of an arbitrary folder that you specify. This server can have:

  • Local static Web content
  • Loose Razor pages (optional)
  • Markdown pages (optional)

In addition, it also provides what, for me, is the most useful feature:

  • Live reload of changed content (optional)

The live reload functionality is built-in, enabled by default, and automatically refreshes any active HTML pages loaded through the server when an HTML page or any other related resource like CSS or JavaScript are changed. This makes it a great, generic tool to use on older non-build process websites or tools you might need to run locally to add functionality and make changes.

As a .NET Core Tool, it's easy to install the server and it's very quick to run and start up.

A standalone local Web server isn't a new idea, as there have been static Node.js-based servers like http-server (https://github.com/http-party/http-server) or browser-sync (https://www.browsersync.io/) forever, but these tools require Node,js and the standalone live reload tools like BrowserSync I've used don't work very reliably. LiveReloadServer is an alternative and it addresses all these scenarios nicely.

To use Live Reload Server:

dotnet tool install -g LiveReloadServer

To run it, you simply point it at a --WebRoot folder on your local computer and that folder then becomes the content source for the website. Figure 13 shows the LiveReload server running with requests firing through it.

The Live Reload functionality is enabled by default so you can edit static text files and immediately see the changes reflected in active browser pages. If you have Razor Pages and/or Markdown Page processing enabled, you can edit Razor and Markdown pages and see those pages refreshed immediately as well.

Because LiveReloadServer is a .NET Core Tool, it also works great on Mac and Linux even though I originally built it for my local Windows set up. After making some very minor adjustments for pathing for Mac and Linux support, the server now also works on those platforms.

By default, the server runs as a local computer Web server, but it can also expose an external port, so it can also be used to host externally accessible sites. This is great for giving network access to other users on your internal network, or for applications that need to expose Web server functionality. The server binaries can also be hosted as full Web applications in IIS or other external front end servers like NGINX, because it's essentially an ASP.NET Core-hosted application.

LiveReloadServer is a simple, generic local Web server you can point at a local folder to host a website.

A Legacy Web and Application Server

The final example is for a legacy application server running as a .NET Core Tool. It's for an ancient integration tool that has recently been updated to .NET Core as an option. I maintain a FoxPro legacy product called West Wind Web Connection that still has many users - for nearly 25 years now. This is as legacy as it comes, and you may laugh at technology this old, but it's still in use.

Because the tools I created so many years ago extended FoxPro functionality to build Web applications, there are still a lot of existing applications that use large FoxPro code bases, haven't been updated, and just keep ticking along. These tools have been kept current and continue to allow these ancient applications to keep working without major disruption or requiring complete re-writes on other platforms for which there is often no budget, technical skill, or incentive.

Web Connection has, for many years, used .NET technologies to provide the interface between a Web Server (IIS only in the past) and FoxPro and the tech using .NET and COM (ugh) is surprisingly stable and reliable. So, when .NET Core came out a few years ago, it offered several new opportunities to extend the Web Server interface tooling Web Connection implements by:

  • Providing a fully self-contained development server
  • Providing a nearly zero configuration environment
  • Its ability to run the server component on non-Windows computers
  • Its ability to run a local computer or network server without requiring IIS
  • Its ability to run truly local Web applications like desktop applications

Long story short, a .NET Core Tool turned out to be great delivery mechanism for someone who needs to run an old application that was built with Web Connection, but doesn't have access or can't install IIS on a computer and most of all, who doesn't want to set up and configure IIS.

This sounds strange, but it's a very common scenario: A user calls and says they have a Web Connection application that was developed 15 years ago, the developer left, and they need to run the application and perhaps make a few changes. Setting up an environment in the past wasn't the easiest thing in the world. With this new component, I can whittle that down to:

  • Install the .NET Core SDK.
  • Install dotnet tool install -g WebConnection.
  • Point at a Web Connection folder and go.

A .NET Core Tool here offers a smooth solution to distribute a server that can then be used to serve an ancient legacy application without complex configuration or special installations required. On the local computer, it's literally: point at a Web Connection application folder and go - no further configuration is required. The same server implementation can also be deployed in a live environment with IIS.

The internal server implementation is very similar to the Live Reload server but extended to handle the Web Connection server protocols so it can handle Web Connection-specific script handling and request routing that lets FoxPro server code execute in response to Web requests. The .NET Core implementation was moved from a .NET HTTP Handler to .NET Core Middleware, and it was surprisingly easy with 95% code reuse from the existing handler.

Legacy technology is always an eye roller, and I doubt that any of you will use this technology, but it makes for an interesting use case of the .NET Core Tool functionality in a very unconventional scenario.

Summary

.NET Core Tools provide a great way to share executable code from .NET Core in an easy and platform-independent way. If you've built a NuGet package and published it before, you already know how to build and share a .NET Core Tool. .NET Core Tools are easy to consume, which gives access to a variety of existing tools and, because they're so easy to share, promote a community of tools to be created.

Hopefully, this article has given you some ideas of tools that you might want to use, or better yet, create and share your own with the community or even just within your organization.