```bash
# dotnet-solution-navigation
Teaches agents to orient in .NET solutions: finding entry points, parsing solution files, traversing project dependencies, locating configuration files, and recognizing common solution layouts. Each subsection includes discovery commands/heuristics and example output.
## Scope
- Entry point discovery (Program.cs, top-level statements, worker services)
- Solution file parsing (.sln, .slnx)
- Project dependency graph traversal
- Configuration file location (appsettings.json, launchSettings.json)
## Out of scope
- Project file structure and modification -- see [skill:dotnet-csproj-reading]
- Project organization decisions and SDK selection -- see [skill:dotnet-project-structure]
- Test framework configuration and test type decisions -- see [skill:dotnet-testing-strategy]
## Prerequisites
.NET 8.0+ SDK. `dotnet` CLI available on PATH. Familiarity with SDK-style projects.
Cross-references: [skill:dotnet-project-structure] for project organization guidance, [skill:dotnet-csproj-reading] for reading and modifying .csproj files found during navigation, [skill:dotnet-testing-strategy] for test project identification and test type decisions.
---
## Subsection 1: Entry Point Discovery
.NET applications can start from several patterns. Do not assume every app has a traditional `Program.cs` with a `Main` method.
### Pattern 1: Traditional Program.cs with Main Method
Used in older projects, worker services, and when explicit control over hosting is needed.
**Discovery command:**
```bash
# Find Program.cs files containing a Main method
grep -rn "static.*void Main\|static.*Task Main\|static.*async.*Main" --include="*.cs" .
```bash
**Example output:**
```text
src/MyApp.Worker/Program.cs:5: public static async Task Main(string[] args)
src/MyApp.Console/Program.cs:3: static void Main(string[] args)
```csharp
### Pattern 2: Top-Level Statements (C# 9+)
Modern .NET projects (templates since .NET 6) use top-level statements -- the file contains no class or Main method, just executable code.
**Discovery command:**
```bash
# Find Program.cs files that do NOT contain class/namespace declarations
# (top-level statements have no enclosing class)
for f in $(find . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"); do
if ! grep -Eq '^[[:space:]]*(class|namespace)[[:space:]]' "$f" 2>/dev/null; then
echo "Top-level: $f"
fi
done
```text
**Example output:**
```text
Top-level: ./src/MyApp.Api/Program.cs
Top-level: ./src/MyApp.Web/Program.cs
```csharp
**Typical content of a top-level Program.cs:**
```csharp
// No namespace, no class, no Main -- this IS the entry point
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
```text
### Pattern 3: Worker Services and Background Hosts
Worker services use `Host.CreateDefaultBuilder` or `Host.CreateApplicationBuilder` without a web server. They appear as `Exe` output type with `Microsoft.NET.Sdk.Worker` SDK.
**Discovery command:**
```bash
# Find worker service projects by SDK type
grep -rn 'Sdk="Microsoft.NET.Sdk.Worker"' --include="*.csproj" .
# Or find IHostedService/BackgroundService implementations
grep -rn "BackgroundService\|IHostedService" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"
```csharp
**Example output:**
```text
src/MyApp.Worker/MyApp.Worker.csproj:1:<Project Sdk="Microsoft.NET.Sdk.Worker">
src/MyApp.Worker/Services/OrderProcessor.cs:8:public class OrderProcessor : BackgroundService
src/MyApp.Worker/Services/EmailSender.cs:5:public class EmailSender : IHostedService
```csharp
### Pattern 4: Test Projects
Test projects are entry points for `dotnet test`. They may not have a `Program.cs` at all -- the test runner provides the entry point.
**Discovery command:**
```bash
# Find test projects by IsTestProject property or test SDK references
grep -rn "<IsTestProject>true</IsTestProject>" --include="*.csproj" .
grep -rn "Microsoft.NET.Test.Sdk\|xunit\|NUnit\|MSTest" --include="*.csproj" . | grep -v "obj/" # Matches both xunit.v3 and legacy xunit
```bash
**Example output:**
```text
tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:5: <IsTestProject>true</IsTestProject>
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:8: <PackageReference Include="xunit.v3" />
```csharp
### Summary Heuristic
When orienting in a new .NET solution, run these commands in sequence:
```bash
# 1. Find all .csproj files
find . -name "*.csproj" -not -path "*/obj/*" | sort
# 2. Identify output types (Exe = app entry point, Library = dependency)
grep -rn "<OutputType>" --include="*.csproj" .
# 3. Find all Program.cs files
find . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"
# 4. Identify test projects
grep -rn "<IsTestProject>true" --include="*.csproj" .
```csharp
---
## Subsection 2: Solution File Formats
.NET solutions use `.sln` (text-based, legacy format) or `.slnx` (XML-based, .NET 9+ preview). Both files list projects and their relationships.
### .sln Format
The traditional solution format is a text file with a custom syntax (not XML).
**Discovery and parsing commands:**
```bash
# Find solution files
find . -name "*.sln" -maxdepth 2
# List all projects in a solution using dotnet CLI
dotnet sln list
# Or specify the solution file explicitly:
dotnet sln MyApp.sln list
```text
**Example output of `dotnet sln list`:**
```text
Project(s)
----------
src/MyApp.Api/MyApp.Api.csproj
src/MyApp.Core/MyApp.Core.csproj
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj
tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj
```csharp
**Reading the .sln file directly** (useful when `dotnet sln list` is not available):
```bash
# Extract project entries from .sln file
grep "^Project(" MyApp.sln
```bash
**Example output:**
```text
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Api", "src\MyApp.Api\MyApp.Api.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Core", "src\MyApp.Core\MyApp.Core.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
```csharp
The GUID `{FAE04EC0-...}` identifies C# projects. The second value is the relative path to the `.csproj` file.
### .slnx Format (.NET 9+)
The `.slnx` format is an XML-based solution file introduced as a preview feature in .NET 9.
**Discovery and parsing commands:**
```bash
# Find .slnx files
find . -name "*.slnx" -maxdepth 2
# dotnet sln commands work with .slnx files too
dotnet sln MyApp.slnx list
```bash
**Example .slnx content:**
```xml
<Solution>
<Folder Name="/src/">
<Project Path="src/MyApp.Api/MyApp.Api.csproj" />
<Project Path="src/MyApp.Core/MyApp.Core.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj" />
</Folder>
</Solution>
```csharp
**Key differences from .sln:**
| Feature | .sln | .slnx |
|---------|------|-------|
| Format | Custom text | XML |
| Readability | Low (GUIDs, custom syntax) | High (clean XML) |
| Availability | All .NET versions | .NET 9+ preview |
| Tooling | Full support | Partial (growing) |
| Solution folders | Nested GUID references | `<Folder>` elements |
### When No Solution File Exists
Some repositories use individual `.csproj` files without a `.sln`. Build and run from project directories:
```bash
# If no .sln exists, find all .csproj files and build individually
find . -name "*.csproj" -not -path "*/obj/*" | sort
dotnet build src/MyApp.Api/MyApp.Api.csproj
```bash
---
## Subsection 3: Project Dependency Traversal
Understanding `ProjectReference` chains is critical for determining build order, finding shared code, and identifying the impact of changes.
### Discovery Commands
```bash
# Find all ProjectReference entries across the solution
grep -rn "<ProjectReference" --include="*.csproj" . | grep -v "obj/"
```bash
**Example output:**
```text
src/MyApp.Api/MyApp.Api.csproj:12: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
src/MyApp.Api/MyApp.Api.csproj:13: <ProjectReference Include="../MyApp.Infrastructure/MyApp.Infrastructure.csproj" />
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:14: <ProjectReference Include="../../src/MyApp.Api/MyApp.Api.csproj" />
```csharp
### Building a Dependency Graph
From the above output, the dependency graph is:
```text
MyApp.Api.Tests
-> MyApp.Api
-> MyApp.Core
-> MyApp.Infrastructure
-> MyApp.Core
```text
**Automated traversal using `dotnet list reference`:**
```bash
# List direct references for a specific project
dotnet list src/MyApp.Api/MyApp.Api.csproj reference
```bash
**Example output:**
```text
Project reference(s)
--------------------
../MyApp.Core/MyApp.Core.csproj
../MyApp.Infrastructure/MyApp.Infrastructure.csproj
```csharp
**Full transitive dependency analysis:**
```bash
# Build the full dependency tree by traversing transitively
# Start from the top-level project and follow each reference
dotnet list src/MyApp.Api/MyApp.Api.csproj reference
dotnet list src/MyApp.Infrastructure/MyApp.Infrastructure.csproj reference
# Continue until you reach projects with no ProjectReference entries
```csharp
### Impact Analysis
When modifying a shared project like `MyApp.Core`, all projects that reference it (directly or transitively) are affected:
```bash
# Find all projects that reference a specific project
grep -rn "MyApp.Core.csproj" --include="*.csproj" . | grep -v "obj/"
```bash
**Example output:**
```text
src/MyApp.Api/MyApp.Api.csproj:12: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:14: <ProjectReference Include="../../src/MyApp.Core/MyApp.Core.csproj" />
```csharp
This means changes to `MyApp.Core` require testing `MyApp.Api`, `MyApp.Infrastructure`, and `MyApp.Core.Tests`.
---
## Subsection 4: Configuration File Locations
.NET projects use several configuration files scattered across the solution. Knowing where to find them is essential for understanding application behavior.
### appsettings*.json
**Discovery command:**
```bash
# Find all appsettings files
find . -name "appsettings*.json" -not -path "*/obj/*" -not -path "*/bin/*" | sort
```bash
**Example output:**
```text
./src/MyApp.Api/appsettings.json
./src/MyApp.Api/appsettings.Development.json
./src/MyApp.Api/appsettings.Production.json
./src/MyApp.Worker/appsettings.json
```json
**Key behavior:** Environment-specific files (`appsettings.{ENVIRONMENT}.json`) override values from the base `appsettings.json`. The environment is set via `DOTNET_ENVIRONMENT` or `ASPNETCORE_ENVIRONMENT`.
### launchSettings.json
**Discovery command:**
```bash
# Find launch settings (inside Properties/ folder of each project)
find . -name "launchSettings.json" -not -path "*/obj/*" -not -path "*/bin/*"
```bash
**Example output:**
```text
./src/MyApp.Api/Properties/launchSettings.json
./src/MyApp.Web/Properties/launchSettings.json
```json
**Key behavior:** Used by `dotnet run` and Visual Studio to configure launch profiles (ports, environment variables, launch URLs). Not deployed to production.
### Directory.Build.props and Directory.Build.targets
**Discovery command:**
```bash
# Find all Directory.Build.props/targets files (may exist at multiple levels)
find . -name "Directory.Build.props" -o -name "Directory.Build.targets" | sort
```bash
**Example output:**
```text
./Directory.Build.props
./Directory.Build.targets
./src/Directory.Build.props
./tests/Directory.Build.props
```xml
**Key behavior:** MSBuild imports the nearest file found walking upward from the project directory. Nested files shadow parent files unless they explicitly import the parent (see [skill:dotnet-csproj-reading] for chaining).
### Other Configuration Files
```bash
# Find all .NET configuration files in one sweep
find . \( -name "nuget.config" -o -name "global.json" -o -name ".editorconfig" \
-o -name "Directory.Packages.props" \) -not -path "*/obj/*" | sort
```bash
**Example output:**
```text
./.editorconfig
./Directory.Packages.props
./global.json
./nuget.config
./src/.editorconfig
```json
| File | Purpose | Resolution |
|------|---------|-----------|
| `nuget.config` | NuGet package sources and mappings | Hierarchical upward from project dir |
| `global.json` | SDK version pinning | Nearest file walking upward |
| `.editorconfig` | Code style and analyzer severity | Hierarchical (sections merge upward) |
| `Directory.Packages.props` | Central package version management | Hierarchical upward from project dir |
---
## Subsection 5: Common Solution Layouts
Recognizing the layout pattern helps agents navigate unfamiliar codebases faster.
### Pattern 1: src/tests Layout
The most common layout. Source projects in `src/`, test projects in `tests/`, mirroring names.
```text
MyApp/
MyApp.sln
Directory.Build.props
Directory.Packages.props
global.json
nuget.config
.editorconfig
src/
MyApp.Api/
MyApp.Api.csproj
Program.cs
Controllers/
Services/
MyApp.Core/
MyApp.Core.csproj
Models/
Interfaces/
MyApp.Infrastructure/
MyApp.Infrastructure.csproj
Data/
Repositories/
tests/
MyApp.Api.Tests/
MyApp.Api.Tests.csproj
MyApp.Core.Tests/
MyApp.Core.Tests.csproj
docs/
architecture.md
```csharp
**Heuristics:**
- `src/` and `tests/` directories at root level.
- Test project names mirror source project names with `.Tests` suffix.
- Shared build config (`Directory.Build.props`, `global.json`) at the root.
**Discovery:**
```bash
# Detect src/tests layout
ls -d src/ tests/ 2>/dev/null && echo "src/tests layout detected"
```bash
### Pattern 2: Vertical Slice Layout
Organizes code by feature rather than by technical layer. Each slice contains its own models, handlers, and endpoints.
```text
MyApp/
MyApp.sln
src/
MyApp.Api/
MyApp.Api.csproj
Program.cs
Features/
Orders/
CreateOrder.cs # Handler + request + response
GetOrder.cs
OrderValidator.cs
OrderEndpoints.cs # Minimal API endpoint mapping
Products/
CreateProduct.cs
ListProducts.cs
ProductEndpoints.cs
Common/
Behaviors/
ValidationBehavior.cs
Middleware/
ExceptionMiddleware.cs
tests/
MyApp.Api.Tests/
Features/
Orders/
CreateOrderTests.cs
GetOrderTests.cs
```csharp
**Heuristics:**
- `Features/` directory within a project.
- Each feature folder contains multiple related files (handler, validator, endpoint).
- Tests mirror the feature folder structure.
**Discovery:**
```bash
# Detect vertical slice layout
find . -type d -name "Features" -not -path "*/obj/*" -not -path "*/bin/*"
```bash
### Pattern 3: Modular Monolith
Multiple bounded contexts as separate projects within a single solution, communicating through explicit interfaces or a shared message bus.
```text
MyApp/
MyApp.sln
src/
MyApp.Host/
MyApp.Host.csproj # Composition root -- references all modules
Program.cs
Modules/
Ordering/
MyApp.Ordering/
MyApp.Ordering.csproj
OrderingModule.cs # Module registration (DI, endpoints)
Domain/
Application/
Infrastructure/
MyApp.Ordering.Tests/
Catalog/
MyApp.Catalog/
MyApp.Catalog.csproj
CatalogModule.cs
Domain/
Application/
Infrastructure/
MyApp.Catalog.Tests/
MyApp.Shared/
MyApp.Shared.csproj # Cross-cutting contracts (events, interfaces)
```csharp
**Heuristics:**
- `Modules/` directory with self-contained bounded contexts.
- A `Host` or `Startup` project that references all modules.
- A `Shared` project for cross-module contracts.
**Discovery:**
```bash
# Detect modular monolith layout
find . -type d -name "Modules" -not -path "*/obj/*" -not -path "*/bin/*"
# Or look for module registration patterns
grep -rn "Module\|AddModule\|RegisterModule" --include="*.cs" . | grep -v "obj/" | head -10
```csharp
---
## Slopwatch Anti-Patterns
These patterns in test project discovery indicate an agent is hiding testing gaps rather than addressing them. See [skill:dotnet-slopwatch] for the automated quality gate that detects these patterns.
### Disabled or Skipped Tests in Test Project Discovery
When navigating a solution and identifying test projects, watch for tests that exist but are silently disabled:
```csharp
// RED FLAG: skipped tests that will not run during dotnet test
[Fact(Skip = "Flaky -- revisit later")]
public async Task ProcessOrder_ConcurrentRequests_HandledCorrectly() { }
// RED FLAG: entire test class disabled via conditional compilation
#if false
public class OrderIntegrationTests
{
[Fact]
public async Task CreateOrder_PersistsToDatabase() { }
}
#endif
// RED FLAG: commented-out test methods
// [Fact]
// public void CalculateDiscount_NegativeAmount_ThrowsException() { }
```text
**Discovery commands to check for disabled tests:**
```bash
# Find skipped tests
grep -rEn 'Skip[[:space:]]*=' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"
# Find tests hidden behind #if false
grep -rn "#if false" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"
# Find commented-out test attributes
grep -rEn '//[[:space:]]*\[(Fact|Theory|Test)\]' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"
```csharp
**Fix:** Investigate why tests are disabled. If they are flaky due to timing, fix the non-determinism or use `[Retry]` (xUnit v3). If they test removed functionality, delete them. Never leave disabled tests as invisible technical debt.
---
## Cross-References
- [skill:dotnet-project-structure] -- project organization, SDK selection, solution layout decisions
- [skill:dotnet-csproj-reading] -- reading and modifying .csproj files found during navigation
- [skill:dotnet-testing-strategy] -- test project identification, test types, test organization
## References
- [.NET Project SDK Overview](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview)
- [dotnet sln Command](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln)
- [.slnx Solution Format](https://learn.microsoft.com/en-us/visualstudio/ide/reference/solution-file-slnx)
- [Configuration in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/)
- [Directory.Build.props/targets](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory)
Dotnet Solution Navigation
Orients in .NET solutions -- entry points, .sln/.slnx, dependency graphs, config.
Dotnet Solution Navigation by rudironsoni · 0bd4bf6
npx skillmds@latest add rudironsoni/dotnet-solution-navigation-2 File contents
---name: dotnet-solution-navigation-2description: Orients in .NET solutions -- entry points, .sln/.slnx, dependency graphs, config.---````! find . -maxdepth 2 ( -name "*.sln" -o -name "*.slnx" ) 2>/dev/null | head -5```bash# dotnet-solution-navigationTeaches agents to orient in .NET solutions: finding entry points, parsing solution files, traversing project dependencies, locating configuration files, and recognizing common solution layouts. Each subsection includes discovery commands/heuristics and example output.## Scope- Entry point discovery (Program.cs, top-level statements, worker services)- Solution file parsing (.sln, .slnx)- Project dependency graph traversal- Configuration file location (appsettings.json, launchSettings.json)## Out of scope- Project file structure and modification -- see [skill:dotnet-csproj-reading]- Project organization decisions and SDK selection -- see [skill:dotnet-project-structure]- Test framework configuration and test type decisions -- see [skill:dotnet-testing-strategy]## Prerequisites.NET 8.0+ SDK. `dotnet` CLI available on PATH. Familiarity with SDK-style projects.Cross-references: [skill:dotnet-project-structure] for project organization guidance, [skill:dotnet-csproj-reading] for reading and modifying .csproj files found during navigation, [skill:dotnet-testing-strategy] for test project identification and test type decisions.---## Subsection 1: Entry Point Discovery.NET applications can start from several patterns. Do not assume every app has a traditional `Program.cs` with a `Main` method.### Pattern 1: Traditional Program.cs with Main MethodUsed in older projects, worker services, and when explicit control over hosting is needed.**Discovery command:**```bash# Find Program.cs files containing a Main methodgrep -rn "static.*void Main\|static.*Task Main\|static.*async.*Main" --include="*.cs" .```bash**Example output:**```textsrc/MyApp.Worker/Program.cs:5: public static async Task Main(string[] args)src/MyApp.Console/Program.cs:3: static void Main(string[] args)```csharp### Pattern 2: Top-Level Statements (C# 9+)Modern .NET projects (templates since .NET 6) use top-level statements -- the file contains no class or Main method, just executable code.**Discovery command:**```bash# Find Program.cs files that do NOT contain class/namespace declarations# (top-level statements have no enclosing class)for f in $(find . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"); do if ! grep -Eq '^[[:space:]]*(class|namespace)[[:space:]]' "$f" 2>/dev/null; then echo "Top-level: $f" fidone```text**Example output:**```textTop-level: ./src/MyApp.Api/Program.csTop-level: ./src/MyApp.Web/Program.cs```csharp**Typical content of a top-level Program.cs:**```csharp// No namespace, no class, no Main -- this IS the entry pointvar builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers();var app = builder.Build();app.MapControllers();app.Run();```text### Pattern 3: Worker Services and Background HostsWorker services use `Host.CreateDefaultBuilder` or `Host.CreateApplicationBuilder` without a web server. They appear as `Exe` output type with `Microsoft.NET.Sdk.Worker` SDK.**Discovery command:**```bash# Find worker service projects by SDK typegrep -rn 'Sdk="Microsoft.NET.Sdk.Worker"' --include="*.csproj" .# Or find IHostedService/BackgroundService implementationsgrep -rn "BackgroundService\|IHostedService" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"```csharp**Example output:**```textsrc/MyApp.Worker/MyApp.Worker.csproj:1:<Project Sdk="Microsoft.NET.Sdk.Worker">src/MyApp.Worker/Services/OrderProcessor.cs:8:public class OrderProcessor : BackgroundServicesrc/MyApp.Worker/Services/EmailSender.cs:5:public class EmailSender : IHostedService```csharp### Pattern 4: Test ProjectsTest projects are entry points for `dotnet test`. They may not have a `Program.cs` at all -- the test runner provides the entry point.**Discovery command:**```bash# Find test projects by IsTestProject property or test SDK referencesgrep -rn "<IsTestProject>true</IsTestProject>" --include="*.csproj" .grep -rn "Microsoft.NET.Test.Sdk\|xunit\|NUnit\|MSTest" --include="*.csproj" . | grep -v "obj/" # Matches both xunit.v3 and legacy xunit```bash**Example output:**```texttests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:5: <IsTestProject>true</IsTestProject>tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:8: <PackageReference Include="xunit.v3" />```csharp### Summary HeuristicWhen orienting in a new .NET solution, run these commands in sequence:```bash# 1. Find all .csproj filesfind . -name "*.csproj" -not -path "*/obj/*" | sort# 2. Identify output types (Exe = app entry point, Library = dependency)grep -rn "<OutputType>" --include="*.csproj" .# 3. Find all Program.cs filesfind . -name "Program.cs" -not -path "*/obj/*" -not -path "*/bin/*"# 4. Identify test projectsgrep -rn "<IsTestProject>true" --include="*.csproj" .```csharp---## Subsection 2: Solution File Formats.NET solutions use `.sln` (text-based, legacy format) or `.slnx` (XML-based, .NET 9+ preview). Both files list projects and their relationships.### .sln FormatThe traditional solution format is a text file with a custom syntax (not XML).**Discovery and parsing commands:**```bash# Find solution filesfind . -name "*.sln" -maxdepth 2# List all projects in a solution using dotnet CLIdotnet sln list# Or specify the solution file explicitly:dotnet sln MyApp.sln list```text**Example output of `dotnet sln list`:**```textProject(s)----------src/MyApp.Api/MyApp.Api.csprojsrc/MyApp.Core/MyApp.Core.csprojsrc/MyApp.Infrastructure/MyApp.Infrastructure.csprojtests/MyApp.Api.Tests/MyApp.Api.Tests.csprojtests/MyApp.Core.Tests/MyApp.Core.Tests.csproj```csharp**Reading the .sln file directly** (useful when `dotnet sln list` is not available):```bash# Extract project entries from .sln filegrep "^Project(" MyApp.sln```bash**Example output:**```textProject("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Api", "src\MyApp.Api\MyApp.Api.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Core", "src\MyApp.Core\MyApp.Core.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"```csharpThe GUID `{FAE04EC0-...}` identifies C# projects. The second value is the relative path to the `.csproj` file.### .slnx Format (.NET 9+)The `.slnx` format is an XML-based solution file introduced as a preview feature in .NET 9.**Discovery and parsing commands:**```bash# Find .slnx filesfind . -name "*.slnx" -maxdepth 2# dotnet sln commands work with .slnx files toodotnet sln MyApp.slnx list```bash**Example .slnx content:**```xml<Solution> <Folder Name="/src/"> <Project Path="src/MyApp.Api/MyApp.Api.csproj" /> <Project Path="src/MyApp.Core/MyApp.Core.csproj" /> </Folder> <Folder Name="/tests/"> <Project Path="tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj" /> </Folder></Solution>```csharp**Key differences from .sln:**| Feature | .sln | .slnx ||---------|------|-------|| Format | Custom text | XML || Readability | Low (GUIDs, custom syntax) | High (clean XML) || Availability | All .NET versions | .NET 9+ preview || Tooling | Full support | Partial (growing) || Solution folders | Nested GUID references | `<Folder>` elements |### When No Solution File ExistsSome repositories use individual `.csproj` files without a `.sln`. Build and run from project directories:```bash# If no .sln exists, find all .csproj files and build individuallyfind . -name "*.csproj" -not -path "*/obj/*" | sortdotnet build src/MyApp.Api/MyApp.Api.csproj```bash---## Subsection 3: Project Dependency TraversalUnderstanding `ProjectReference` chains is critical for determining build order, finding shared code, and identifying the impact of changes.### Discovery Commands```bash# Find all ProjectReference entries across the solutiongrep -rn "<ProjectReference" --include="*.csproj" . | grep -v "obj/"```bash**Example output:**```textsrc/MyApp.Api/MyApp.Api.csproj:12: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />src/MyApp.Api/MyApp.Api.csproj:13: <ProjectReference Include="../MyApp.Infrastructure/MyApp.Infrastructure.csproj" />src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />tests/MyApp.Api.Tests/MyApp.Api.Tests.csproj:14: <ProjectReference Include="../../src/MyApp.Api/MyApp.Api.csproj" />```csharp### Building a Dependency GraphFrom the above output, the dependency graph is:```textMyApp.Api.Tests -> MyApp.Api -> MyApp.Core -> MyApp.Infrastructure -> MyApp.Core```text**Automated traversal using `dotnet list reference`:**```bash# List direct references for a specific projectdotnet list src/MyApp.Api/MyApp.Api.csproj reference```bash**Example output:**```textProject reference(s)--------------------../MyApp.Core/MyApp.Core.csproj../MyApp.Infrastructure/MyApp.Infrastructure.csproj```csharp**Full transitive dependency analysis:**```bash# Build the full dependency tree by traversing transitively# Start from the top-level project and follow each referencedotnet list src/MyApp.Api/MyApp.Api.csproj referencedotnet list src/MyApp.Infrastructure/MyApp.Infrastructure.csproj reference# Continue until you reach projects with no ProjectReference entries```csharp### Impact AnalysisWhen modifying a shared project like `MyApp.Core`, all projects that reference it (directly or transitively) are affected:```bash# Find all projects that reference a specific projectgrep -rn "MyApp.Core.csproj" --include="*.csproj" . | grep -v "obj/"```bash**Example output:**```textsrc/MyApp.Api/MyApp.Api.csproj:12: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />src/MyApp.Infrastructure/MyApp.Infrastructure.csproj:10: <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />tests/MyApp.Core.Tests/MyApp.Core.Tests.csproj:14: <ProjectReference Include="../../src/MyApp.Core/MyApp.Core.csproj" />```csharpThis means changes to `MyApp.Core` require testing `MyApp.Api`, `MyApp.Infrastructure`, and `MyApp.Core.Tests`.---## Subsection 4: Configuration File Locations.NET projects use several configuration files scattered across the solution. Knowing where to find them is essential for understanding application behavior.### appsettings*.json**Discovery command:**```bash# Find all appsettings filesfind . -name "appsettings*.json" -not -path "*/obj/*" -not -path "*/bin/*" | sort```bash**Example output:**```text./src/MyApp.Api/appsettings.json./src/MyApp.Api/appsettings.Development.json./src/MyApp.Api/appsettings.Production.json./src/MyApp.Worker/appsettings.json```json**Key behavior:** Environment-specific files (`appsettings.{ENVIRONMENT}.json`) override values from the base `appsettings.json`. The environment is set via `DOTNET_ENVIRONMENT` or `ASPNETCORE_ENVIRONMENT`.### launchSettings.json**Discovery command:**```bash# Find launch settings (inside Properties/ folder of each project)find . -name "launchSettings.json" -not -path "*/obj/*" -not -path "*/bin/*"```bash**Example output:**```text./src/MyApp.Api/Properties/launchSettings.json./src/MyApp.Web/Properties/launchSettings.json```json**Key behavior:** Used by `dotnet run` and Visual Studio to configure launch profiles (ports, environment variables, launch URLs). Not deployed to production.### Directory.Build.props and Directory.Build.targets**Discovery command:**```bash# Find all Directory.Build.props/targets files (may exist at multiple levels)find . -name "Directory.Build.props" -o -name "Directory.Build.targets" | sort```bash**Example output:**```text./Directory.Build.props./Directory.Build.targets./src/Directory.Build.props./tests/Directory.Build.props```xml**Key behavior:** MSBuild imports the nearest file found walking upward from the project directory. Nested files shadow parent files unless they explicitly import the parent (see [skill:dotnet-csproj-reading] for chaining).### Other Configuration Files```bash# Find all .NET configuration files in one sweepfind . \( -name "nuget.config" -o -name "global.json" -o -name ".editorconfig" \ -o -name "Directory.Packages.props" \) -not -path "*/obj/*" | sort```bash**Example output:**```text./.editorconfig./Directory.Packages.props./global.json./nuget.config./src/.editorconfig```json| File | Purpose | Resolution ||------|---------|-----------|| `nuget.config` | NuGet package sources and mappings | Hierarchical upward from project dir || `global.json` | SDK version pinning | Nearest file walking upward || `.editorconfig` | Code style and analyzer severity | Hierarchical (sections merge upward) || `Directory.Packages.props` | Central package version management | Hierarchical upward from project dir |---## Subsection 5: Common Solution LayoutsRecognizing the layout pattern helps agents navigate unfamiliar codebases faster.### Pattern 1: src/tests LayoutThe most common layout. Source projects in `src/`, test projects in `tests/`, mirroring names.```textMyApp/ MyApp.sln Directory.Build.props Directory.Packages.props global.json nuget.config .editorconfig src/ MyApp.Api/ MyApp.Api.csproj Program.cs Controllers/ Services/ MyApp.Core/ MyApp.Core.csproj Models/ Interfaces/ MyApp.Infrastructure/ MyApp.Infrastructure.csproj Data/ Repositories/ tests/ MyApp.Api.Tests/ MyApp.Api.Tests.csproj MyApp.Core.Tests/ MyApp.Core.Tests.csproj docs/ architecture.md```csharp**Heuristics:**- `src/` and `tests/` directories at root level.- Test project names mirror source project names with `.Tests` suffix.- Shared build config (`Directory.Build.props`, `global.json`) at the root.**Discovery:**```bash# Detect src/tests layoutls -d src/ tests/ 2>/dev/null && echo "src/tests layout detected"```bash### Pattern 2: Vertical Slice LayoutOrganizes code by feature rather than by technical layer. Each slice contains its own models, handlers, and endpoints.```textMyApp/ MyApp.sln src/ MyApp.Api/ MyApp.Api.csproj Program.cs Features/ Orders/ CreateOrder.cs # Handler + request + response GetOrder.cs OrderValidator.cs OrderEndpoints.cs # Minimal API endpoint mapping Products/ CreateProduct.cs ListProducts.cs ProductEndpoints.cs Common/ Behaviors/ ValidationBehavior.cs Middleware/ ExceptionMiddleware.cs tests/ MyApp.Api.Tests/ Features/ Orders/ CreateOrderTests.cs GetOrderTests.cs```csharp**Heuristics:**- `Features/` directory within a project.- Each feature folder contains multiple related files (handler, validator, endpoint).- Tests mirror the feature folder structure.**Discovery:**```bash# Detect vertical slice layoutfind . -type d -name "Features" -not -path "*/obj/*" -not -path "*/bin/*"```bash### Pattern 3: Modular MonolithMultiple bounded contexts as separate projects within a single solution, communicating through explicit interfaces or a shared message bus.```textMyApp/ MyApp.sln src/ MyApp.Host/ MyApp.Host.csproj # Composition root -- references all modules Program.cs Modules/ Ordering/ MyApp.Ordering/ MyApp.Ordering.csproj OrderingModule.cs # Module registration (DI, endpoints) Domain/ Application/ Infrastructure/ MyApp.Ordering.Tests/ Catalog/ MyApp.Catalog/ MyApp.Catalog.csproj CatalogModule.cs Domain/ Application/ Infrastructure/ MyApp.Catalog.Tests/ MyApp.Shared/ MyApp.Shared.csproj # Cross-cutting contracts (events, interfaces)```csharp**Heuristics:**- `Modules/` directory with self-contained bounded contexts.- A `Host` or `Startup` project that references all modules.- A `Shared` project for cross-module contracts.**Discovery:**```bash# Detect modular monolith layoutfind . -type d -name "Modules" -not -path "*/obj/*" -not -path "*/bin/*"# Or look for module registration patternsgrep -rn "Module\|AddModule\|RegisterModule" --include="*.cs" . | grep -v "obj/" | head -10```csharp---## Slopwatch Anti-PatternsThese patterns in test project discovery indicate an agent is hiding testing gaps rather than addressing them. See [skill:dotnet-slopwatch] for the automated quality gate that detects these patterns.### Disabled or Skipped Tests in Test Project DiscoveryWhen navigating a solution and identifying test projects, watch for tests that exist but are silently disabled:```csharp// RED FLAG: skipped tests that will not run during dotnet test[Fact(Skip = "Flaky -- revisit later")]public async Task ProcessOrder_ConcurrentRequests_HandledCorrectly() { }// RED FLAG: entire test class disabled via conditional compilation#if falsepublic class OrderIntegrationTests{ [Fact] public async Task CreateOrder_PersistsToDatabase() { }}#endif// RED FLAG: commented-out test methods// [Fact]// public void CalculateDiscount_NegativeAmount_ThrowsException() { }```text**Discovery commands to check for disabled tests:**```bash# Find skipped testsgrep -rEn 'Skip[[:space:]]*=' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"# Find tests hidden behind #if falsegrep -rn "#if false" --include="*.cs" . | grep -v "obj/" | grep -v "bin/"# Find commented-out test attributesgrep -rEn '//[[:space:]]*\[(Fact|Theory|Test)\]' --include="*.cs" . | grep -v "obj/" | grep -v "bin/"```csharp**Fix:** Investigate why tests are disabled. If they are flaky due to timing, fix the non-determinism or use `[Retry]` (xUnit v3). If they test removed functionality, delete them. Never leave disabled tests as invisible technical debt.---## Cross-References- [skill:dotnet-project-structure] -- project organization, SDK selection, solution layout decisions- [skill:dotnet-csproj-reading] -- reading and modifying .csproj files found during navigation- [skill:dotnet-testing-strategy] -- test project identification, test types, test organization## References- [.NET Project SDK Overview](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview)- [dotnet sln Command](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln)- [.slnx Solution Format](https://learn.microsoft.com/en-us/visualstudio/ide/reference/solution-file-slnx)- [Configuration in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/)- [Directory.Build.props/targets](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory)````
rudironsoni/ghost/tree/main/.cline/skills/dotnet-solution-navigation commit 0bd4bf6a12
Frequently asked questions
Run npx skillmds@latest add rudironsoni/dotnet-solution-navigation-2 in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Orients in .NET solutions -- entry points, .sln/.slnx, dependency graphs, config. It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
rudironsoni (@rudironsoni) published this skill. Their other Agent Skills are listed on their SkillMD profile.