Managing a .NET Core Project from the Command Line

Share on:

From the day Visual Studio Code was released, I’ve been a huge fan. At that time, I mostly worked with Python projects, which played well with the concept of a lightweight editor. Running tests or code all happened from the command line, which I became used to over the next several years as my projects adopted more other command-line based tools like Terraform.

As .NET Core started to take off, I felt the tug to get back up to speed on all things C#. I had grown attached to VS Code over the years, so I challenged myself to continue using it rather than switching back to Visual Studio. However, all of my previous experience with creating new .NET projects involved the “File -> New Project” menu in Visual Studio, so I decided to compromise. I used Visual Studio to create solutions, projects, and templated classes like API controllers and used VS Code for coding. However, this felt very wrong.

When I started several new personal projects earlier this year, I decided to take the time to better understand the .NET command line experience and find alternative ways to handle tasks that I depended on Visual Studio for. During that time, I found alternatives to most of the functionality that I depended on Visual Studio to provide. I realized that the dotnet command was more useful for more than just dotnet new. I also that where the capabilities of the dotnet command ended, an ecosystem of command-line applications (an unofficial list of tools can be found here) created to support developing .NET Core applications. I wanted to share some of the solutions I found that made working solely from the command line possible.

Solution Management

When using dotnet new to create a new project, one of the first things I noticed missing from the project was a solution file. Given that new usually creates a single project, a solution file isn’t always necessary. However, if you end up creating several projects or are working with someone using Visual Studio, having a solution file becomes more useful. I was pleased to learn that dotnet new can generate solution files as well.

1dotnet new webapi -n CliDemo
2cd CliDemo
3dotnet new sln

Perfect! This creates an empty solution file, so there is a bit more work to be done. While you could manually edit the solution to add a reference to your projects, the dotnet sln command is a more reliable way of adding, listing, and deleting projects from the solution.

1 dotnet sln add .\CliDemo.csproj
2Project `CliDemo.csproj` added to the solution.

Now we can run dotnet sln list to verify the project was added successfully.

1 dotnet sln list

Source Control

While adding source control to a project is a quick git init away, there’s still one thing missing: a .gitignore file. While you could track down the official GitHub repo that has .gitignore files for most language types or just copy one from an old project, the .NET team has thankfully added a dotnet new gitignore command to generate the file for you. It’s one of those nice additions that save time and doesn’t leave you wondering if you found the “right” .gitignore file.

Package Management

Replicating Visual Studio’s NuGet package manager experience turned out to be less challenging than I thought. The NuGet website provides an easy way to search for packages that has the additional benefit of providing the command that needs to be run to add a reference to the package. The nagging issue I had was how to find out out if versions of my packages were out of date. A bit of research lead me to the NuKeeper global tool which provided exactly what I needed.

 1 nukeeper inspect
 2Found 5 packages
 3Found 5 packages in use, 5 distinct, in 1 projects.
 4Json.Net, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.VisualStudio.Web.CodeGeneration.Design, Swashbuckle.AspNetCore
 5Found 2 possible updates
 6Microsoft.EntityFrameworkCore.SqlServer from 3.1.4 to 3.1.8 in CliDemo.csproj
 7Swashbuckle.AspNetCore from 5.5.1 to 5.6.3 in CliDemo.csproj
 9Found 2 package updates
10Microsoft.EntityFrameworkCore.SqlServer to 3.1.8 from 3.1.4 in 1 place since 1 month ago.
11Swashbuckle.AspNetCore to 5.6.3 from 5.5.1 in 1 place since 19 days ago.

Running nukeeper inspect provides a report on which packages are behind their latest versions without performing any updates. If everything looks in order, executing nukeeper update updates the version numbers in the csproj file and downloads the new package versions.

Database Migrations

If you’ve worked with Entity Framework before, you’re likely used to switching to the package manager console in Visual Studio to add or run migrations. The dotnet ef global tool provides the same functionality with similar command syntax.

1dotnet ef migrations add InitialDb
2dotnet ef database update

Controller Scaffolding

I’ll be honest: I can’t write a .NET Core Web API Controller from scratch. My muscle memory expects right-clicking the Controllers directory to pop up the handy Add -> Controller link that Visual Studio provides.

Picture of the Add Controller dialog from Visual Studio

By coincidence, I happened upon a workshop that introduced me to the dotnet-aspnet-codegenerator global tool which provides the same capabilitiy. This tool has dependencies on other NuGet packages, so the package references should be added to the project you are working on.

While searching for a solution, the host of a live coding stream mentioned a workshop that introduced me to the dotnet-aspnet-codegenerator global tool, which provides the same capabilities for generating controllers. This tool has dependencies on other NuGet packages, so the package references should be added to the project you are working on.

1dotnet add package Microsoft.EntityFrameworkCore.Design
2dotnet add package Microsoft.EntityFrameworkCore.SqlServer
3dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
4dotnet tool install -g dotnet-aspnet-codegenerator

This tool assumes that your web project follows the convention of storing data models in a Models directory. You also need to provide the new controller’s name, the path to your Controllers directory, and the namespace of your DbContext. Don’t worry if you don’t haven’t created a DbContext at this point. If the generator determines that the DbContext doesn’t exist, the tool will create one for you.

 1 dotnet aspnet-codegenerator controller -api -name ToolsController -m Tool -dc Data.AppDbContext -outDir Controllers
 2Building project ...
 3Finding the generator 'controller'...
 4Running the generator 'controller'...
 5Generating a new DbContext class 'Data.AppDbContext'
 6Attempting to compile the application in memory with the added DbContext.
 7Attempting to figure out the EntityFramework metadata for the model and DbContext: 'Tool'
 8Added DbContext : '\Data\AppDbContext.cs'
 9Added Controller : '\Controllers\ToolsController.cs'.
10RunTime 00:00:07.58

There’s a lot to unpack here. The tool creates a new DbContext, wires up the new DbContext in Startup.cs, and finally creates the new API controller with the standard create/read/update/delete routes. This approach may not always meet your needs, it is a great way to get quick prototypes up and running.

Wrap Up

.NET has come a long way from being tightly coupled with Visual Studio. Having the command line as an alternative workflow allows those developers to have an experience equal to those working in Visual Studio. To keep this post concise, I only mentioned a few of the global tools I’ve integrated into my workflow. Still, there is a growing ecosystem of tools to handle everything from code formatting, measuring code coverage, or finding just the right gif. Go give them a try!

Good Place Janet waving