.NET
application dependencies
software development
dependency management
programming tips

How do I determine the dependencies of a .NET application?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When a .NET application behaves differently after build or deployment, the problem is often a dependency issue rather than a code bug. The useful way to inspect dependencies is to look at three layers separately: what the project declares, what NuGet resolves, and what the published app actually carries at runtime.

Start with the project file

The .csproj file shows direct dependencies explicitly. In modern SDK-style projects, you will usually see PackageReference and ProjectReference entries.

xml
1<ItemGroup>
2  <PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
3  <PackageReference Include="Dapper" Version="2.1.35" />
4  <ProjectReference Include="..\Shared\Shared.csproj" />
5</ItemGroup>

This tells you what your application asked for directly, but not everything it ended up with. For transitive dependencies, you need the CLI.

Use the dotnet CLI to see resolved packages

The most useful first command is:

bash
dotnet list src/MyApp/MyApp.csproj package

That shows direct NuGet package references. To include transitive packages as well:

bash
dotnet list src/MyApp/MyApp.csproj package --include-transitive

This is often the fastest way to answer questions such as:

  • which package pulled in a particular library
  • why a certain version appeared in restore output
  • whether two projects are resolving different versions of the same package

For application behavior, run this command against the executable project, not just a class library.

Inspect the publish output

Project and restore information are useful, but the publish output is what the runtime actually uses. Publish the app first:

bash
dotnet publish src/MyApp/MyApp.csproj -c Release -o ./artifacts/publish

A published app usually includes files such as:

  • 'MyApp.dll'
  • 'MyApp.runtimeconfig.json'
  • 'MyApp.deps.json'

The .deps.json file is especially important because it records runtime dependency information for the published application.

If you want a quick look at that manifest, open it directly or use a JSON tool:

bash
jq '.libraries | keys[]' ./artifacts/publish/MyApp.deps.json

That helps answer the question "what does the runtime expect to be present" rather than only "what did the project file declare."

Use the right layer for the question

A useful rule is:

  • '.csproj answers what you declared directly'
  • 'dotnet list package --include-transitive answers what NuGet resolved'
  • '.deps.json answers what the published runtime expects'

These are related but not identical views. A package can be restored without contributing a runtime assembly. A project reference can exist only for tests. A target framework condition can change which dependencies appear in output.

That is why dependency debugging gets easier when you stop asking one tool to answer every question.

When dependency graphs get complicated

If package resolution is still unclear, generate a restore graph:

bash
dotnet msbuild src/MyApp/MyApp.csproj \
  -t:GenerateRestoreGraphFile \
  -p:RestoreGraphOutputPath=restore-graph.json

This produces a verbose graph file that is useful when central package management, target framework conditions, or version conflicts make the simpler commands insufficient.

You can also inspect assemblies with tools such as ILSpy if the real question is about assembly references rather than NuGet packages.

Common Pitfalls

The biggest pitfall is checking only the project file and assuming that tells the whole story. It does not reveal transitive dependencies or runtime asset selection.

Another issue is inspecting a library project when the deployment problem belongs to the app project. The executable entry point is the better source of truth for runtime behavior.

It is also easy to forget target frameworks and build configurations. The dependency set for net8.0 Debug may not match what gets published for Release or for a different target framework.

Finally, do not confuse packages with output files. A package may contain assemblies, native assets, analyzers, or build targets, and not all of those end up beside the executable.

Summary

  • Check the .csproj file for direct package and project references.
  • Use dotnet list package --include-transitive to inspect the resolved package graph.
  • Inspect .deps.json in publish output to see runtime dependencies.
  • Generate a restore graph when version resolution is still unclear.
  • Investigate the executable project and exact target framework you actually deploy.

Course illustration
Course illustration

All Rights Reserved.