Back to Blog
.NETASP.NET CoreDotnet CLIC#Spring BootBackendDeveloper ProductivityEntity Framework CoreArchitectureSoftware Engineering

The .NET CLI and Project Structure Guide I Wish I Had When Transitioning from Spring Boot

The .NET CLI and Project Structure Guide I Wish I Had When Transitioning from Spring Boot

1. Introduction: The Learning Curve Nobody Talks About

When I first transitioned from Spring Boot to ASP.NET Core, one of the biggest challenges was not actually C#.

It was understanding the ecosystem.

With Spring Boot, many workflows felt familiar because of Maven, Gradle, application.properties, and the convention-heavy project structure.

In .NET, I suddenly had to understand:

  • the dotnet CLI
  • multiple project templates
  • solution files
  • startup projects
  • launch profiles
  • appsettings.json
  • NuGet package management
  • EF Core tooling
  • multi-project architectures
  • user secrets
  • watch mode
  • different hosting models

At first, the ecosystem felt fragmented.

I remember keeping random .NET CLI commands in Notepad because I constantly forgot them while switching between projects.

Over time, however, I realized something important:

The .NET CLI is one of the most powerful and consistent developer tooling ecosystems available today.

Once the concepts click, productivity improves dramatically.

This article covers the commands, project structures, and workflows I struggled with earlier.

2. Understanding the .NET Ecosystem Structure

One of the first confusing things for developers coming from Spring Boot is that .NET projects are often organized differently.

A typical enterprise .NET solution using the clean architecture structure may look like this:

plaintext
InventoryManagement/
├── InventoryManagement.sln
├── global.json
├── Directory.Build.props
├── Directory.Packages.props
├── .editorconfig
├── README.md
├── .gitignore
├── docs/
│   ├── architecture/
│   ├── api-specs/
│   ├── diagrams/
│   └── decisions/
├── deploy/
│   ├── docker/
│   ├── kubernetes/
│   ├── nginx/
│   └── terraform/
├── scripts/
│   ├── database/
│   ├── setup/
│   ├── migrations/
│   └── ci/
├── src/
│   │
│   ├── BuildingBlocks/
│   │   ├── BuildingBlocks.Logging/
│   │   ├── BuildingBlocks.Messaging/
│   │   ├── BuildingBlocks.Security/
│   │   ├── BuildingBlocks.Observability/
│   │   └── BuildingBlocks.Shared/
│   │
│   ├── Services/
│   │   │
│   │   ├── Identity/
│   │   │   ├── Identity.Api/
│   │   │   ├── Identity.Application/
│   │   │   ├── Identity.Domain/
│   │   │   ├── Identity.Infrastructure/
│   │   │   └── Identity.Contracts/
│   │   │
│   │   ├── Inventory/
│   │   │   ├── Inventory.Api/
│   │   │   ├── Inventory.Application/
│   │   │   ├── Inventory.Domain/
│   │   │   ├── Inventory.Infrastructure/
│   │   │   └── Inventory.Contracts/
│   │   │
│   │   ├── Orders/
│   │   │   ├── Orders.Api/
│   │   │   ├── Orders.Application/
│   │   │   ├── Orders.Domain/
│   │   │   ├── Orders.Infrastructure/
│   │   │   └── Orders.Contracts/
│   │   │
│   │   └── Notifications/
│   │       ├── Notifications.Api/
│   │       ├── Notifications.Application/
│   │       ├── Notifications.Domain/
│   │       ├── Notifications.Infrastructure/
│   │       └── Notifications.Contracts/
│   │
│   ├── ApiGateway/
│   │   └── Gateway.Api/
│   │
│   └── SharedKernel/
│       ├── SharedKernel.Domain/
│       ├── SharedKernel.Application/
│       └── SharedKernel.Contracts/
├── tests/
│   │
│   ├── UnitTests/
│   │   ├── Inventory.UnitTests/
│   │   ├── Orders.UnitTests/
│   │   └── Identity.UnitTests/
│   │
│   ├── IntegrationTests/
│   │   ├── Inventory.IntegrationTests/
│   │   ├── Orders.IntegrationTests/
│   │   └── Identity.IntegrationTests/
│   │
│   ├── ArchitectureTests/
│   └── PerformanceTests/
├── observability/
│   ├── prometheus/
│   ├── grafana/
│   ├── loki/
│   └── otel/
└── .github/
    └── workflows/

i) Important Concepts

a) Solution File (.sln)

The solution file acts like a workspace containing multiple projects.

Think of it as an organizational layer.

b) Project File (.csproj)

Each project has its own .csproj file.

This is roughly comparable to Maven's pom.xml.

The project file defines:

  • dependencies
  • SDK type
  • build settings
  • target frameworks
  • references

ii) Why Multiple Projects Are Common

In enterprise .NET applications, separation of concerns is strongly emphasized.

Typical layers include:

  • API layer
  • Application/business logic
  • Domain models
  • Infrastructure/data access

This structure maps very naturally to Clean Architecture and Domain-Driven Design patterns.

3. Creating Projects with the .NET CLI

The .NET CLI revolves around project templates.

This was initially confusing because there are many different templates depending on the application type.

i) Listing Available Templates

bash
dotnet new list

This shows all installed templates.

ii) Creating Common Project Types

a) ASP.NET Core Web API

bash
dotnet new webapi -n InventoryManagement.Api

b) Console Application

bash
dotnet new console -n DemoApp

c) Class Library

bash
dotnet new classlib -n InventoryManagement.Domain

d) Blazor Application

bash
dotnet new blazor

e) MAUI Application

bash
dotnet new maui

f) gRPC Service

bash
dotnet new grpc

iii) Creating a Solution

bash
dotnet new sln -n InventoryManagement

iv) Adding Projects to the Solution

bash
dotnet sln add src/InventoryManagement.Api/InventoryManagement.Api.csproj

This workflow becomes extremely powerful once you understand how projects connect together.

4. Managing Dependencies with NuGet

NuGet is the package manager for .NET.

Coming from Maven or Gradle, the experience feels surprisingly clean.

i) Installing Packages

bash
dotnet add package Microsoft.EntityFrameworkCore.Design

You can also target a specific project:

bash
dotnet add src/InventoryManagement.Api/InventoryManagement.Api.csproj package Microsoft.EntityFrameworkCore.Design

ii) Removing Packages

bash
dotnet remove package Microsoft.EntityFrameworkCore.Design

iii) Restoring Dependencies

bash
dotnet restore

iv) Updating Packages

Most IDEs handle this visually, but package updates can also be managed via CLI tools.

v) Why This Matters

One thing I eventually appreciated about the .NET ecosystem is the consistency.

Most developer workflows follow the same command structure:

bash
dotnet [verb] [target] [options]

This makes the tooling relatively predictable once the patterns become familiar.

5. Running Applications and Watch Mode

The dotnet run command is straightforward:

However, things become more interesting with watch mode.

i) Watch Mode

bash
dotnet watch run

This automatically rebuilds and restarts the application whenever files change.

For backend API development, this becomes a major productivity improvement.

ii) Launch Profiles

ASP.NET Core projects usually contain:

plaintext
Properties/launchSettings.json

This file defines:

  • ports
  • environment variables
  • launch profiles
  • HTTPS settings

Example:

json
{
  "profiles": {
    "http": {
      "commandName": "Project",
      "applicationUrl": "http://localhost:5000"
    }
  }
}

iii) Running Specific Profiles

bash
dotnet run --launch-profile http

This concept initially confused me because it differs from how Spring Boot profiles work.

Eventually, I realized that .NET separates:

  • environment configuration
  • launch configuration
  • application settings

more explicitly.

6. Understanding appsettings.json and Environment Configuration

Configuration management in .NET is one of the ecosystem's strongest areas.

A typical project may contain:

plaintext
appsettings.json
appsettings.Development.json
appsettings.Production.json

i) Base Configuration

json
{
  "ConnectionStrings": {
    "DefaultConnection": "..."
  }
}

ii) Environment-Specific Overrides

json
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug"
    }
  }
}

iii) Environment Selection

The environment is usually controlled using:

bash
ASPNETCORE_ENVIRONMENT=Development

iv) User Secrets

One feature I quickly appreciated was user secrets.

Instead of hardcoding sensitive configuration locally:

bash
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Host=localhost;Port=5432;Database=inventory_dotnet;Username=karianmash;Password=password"

This stores secrets outside the repository.

This is much cleaner than accidentally committing credentials into source control.

v) Secret Keys

Generating secure values is also easy:

powershell
[guid]::NewGuid().ToString("N")

I used this frequently for JWT secrets and application keys.

7. Entity Framework Core CLI Workflows

Entity Framework Core tooling was another major learning curve.

Initially, I struggled to understand:

  • startup projects
  • migrations
  • database updates
  • multi-project setups

i) Adding Migrations

bash
dotnet ef migrations add InitialCreate

ii) Updating the Database

bash
dotnet ef database update

iii) Multi-Project Architectures

In Clean Architecture setups, migrations often live in the Infrastructure project while the API acts as the startup project.

Example:

bash
dotnet ef migrations add InitialCreate \
  --project src/InventoryManagement.Infrastructure \
  --startup-project src/InventoryManagement.Api

iv) Listing Migrations

bash
dotnet ef migrations list

v) Removing Migrations

bash
dotnet ef migrations remove

vi) Generating SQL Scripts

bash
dotnet ef migrations script

This becomes very useful for:

  • production deployments
  • DBA reviews
  • migration auditing

vii) Important Realization

Eventually I understood: Read more about

EF Core tooling makes much more sense once you understand project boundaries.

Read more about EF Core on my previous article: Link

The confusion often comes from architecture, not the CLI itself.

8. Build, Clean, and Debugging Workflows

Some of the most common commands eventually become muscle memory.

i) Building Projects

bash
dotnet build

ii) Cleaning Build Artifacts

bash
dotnet clean

iii) Running Tests

bash
dotnet test

iv) Restoring Packages

bash
dotnet restore

v) Why These Commands Matter

One thing I appreciated compared to some ecosystems is how unified the tooling feels.

The same CLI handles:

  • project creation
  • dependency management
  • testing
  • builds
  • publishing
  • migrations
  • configuration

This consistency improves developer ergonomics significantly over time.

vi) IDE Integration

Another important realization is that tools like:

  • Visual Studio
  • Rider
  • VS Code

are heavily powered by the same CLI underneath.

Learning the CLI directly makes developers much more independent from the IDE.

9. Practical Commands I Kept in Notepad

During my transition into .NET, I constantly saved some of useful commands mentioned above because I kept forgetting them. At the time, these felt like random scattered commands.

Looking back, they were actually part of learning the operational side of backend engineering.

Eventually, backend development becomes more than writing application code.

You also start learning:

  • infrastructure
  • databases
  • migrations
  • deployment workflows
  • developer tooling
  • environment management
  • automation

10. Conclusion: The CLI Eventually Becomes a Superpower

Transitioning from my previous Spring Boot background to ASP.NET Core initially felt overwhelming because the ecosystem exposed many concepts explicitly.

At first, this felt like complexity.

Over time, however, I realized it was actually flexibility.

The .NET CLI eventually becomes one of the most productive parts of the ecosystem because it provides a consistent interface for:

  • creating applications
  • managing dependencies
  • configuring environments
  • running migrations
  • building projects
  • debugging applications
  • automating workflows

More importantly, learning the CLI teaches developers how the ecosystem actually works underneath the IDE. That understanding becomes incredibly valuable when:

  • debugging build issues
  • working in CI/CD pipelines
  • scaling multi-project systems
  • onboarding into enterprise codebases
  • troubleshooting deployments

The learning curve is real.

But once the mental model clicks, the .NET developer experience becomes extremely powerful.

About the Author

Ian Macharia

Ian Macharia

Admin

Ian is a Senior Software Engineer and Tech Lead specializing in building high-performance APIs, distributed systems, and modern cloud architectures.

Chat on WhatsApp