Assemblies & NuGet

15 questions found

What is an assembly in .NET, and what does it contain?

Beginner
An assembly is the fundamental unit of deployment and versioning in .NET -- a compiled .dll or .exe file containing IL (Intermediate Language) code, type metadata, and a manifest describing the assembly's identity (name, version, culture) and its references to other assemblies. The CLR loads assemblies at runtime to execute the types and members they define.
// Building a project produces an assembly:
dotnet build
// Output: bin/Debug/net8.0/MyApp.dll -- this is the assembly
Real-world example A shared business-logic library is compiled into MyCompany.Core.dll, an assembly referenced by multiple separate application assemblies (web API, background worker, console tool) without duplicating the source code.

Common follow-ups: What's the difference between a private and shared assembly?;How does the CLR locate assemblies at runtime?

.NET CLI SDK & Project Structure (csproj);CLR & Runtime

What is NuGet, and what problem does it solve for .NET developers?

Beginner
NuGet is .NET's official package manager, providing a standardized way to discover, install, update, and share reusable libraries (packages) across projects, avoiding the need to manually download DLLs and manage their dependencies and versions by hand. Packages are hosted on NuGet.org (public) or private feeds (Azure Artifacts, GitHub Packages, internal servers) for proprietary code.
dotnet add package Newtonsoft.Json
// Downloads the package and its dependencies, adds a PackageReference to the .csproj
Real-world example Instead of manually copying a JSON serialization DLL and its dependency DLLs into a project folder, a developer runs one `dotnet add package` command that handles downloading, dependency resolution, and project file updates automatically.

Common follow-ups: How does NuGet resolve version conflicts between transitive dependencies?;What's the difference between NuGet.org and a private feed?

.NET CLI SDK & Project Structure (csproj);Assemblies & NuGet

What is the Global Assembly Cache (GAC), and is it still relevant in modern .NET?

Intermediate
The GAC was a machine-wide repository in .NET Framework for storing strongly-named shared assemblies, letting multiple applications reference one common copy instead of each having a private copy. Modern .NET has no GAC equivalent -- it exclusively uses local, per-application NuGet package references and a local package cache, reflecting the shift toward isolated, side-by-side, self-contained dependency management rather than machine-wide shared assemblies.
// .NET Framework (legacy):
gacutil /i MyAssembly.dll  // installs into machine-wide GAC

// Modern .NET: no GAC -- dependencies resolved from
// the local NuGet package cache (~/.nuget/packages) per-project
Real-world example A team migrating from .NET Framework removes all GAC-installation deployment scripts entirely, since modern .NET's per-application dependency model has no equivalent concept requiring machine-wide assembly registration.

Common follow-ups: Why did Microsoft remove the GAC concept from modern .NET?;What replaced GAC's shared-assembly benefit in containerized deployments?

.NET vs .NET Framework;CLR & Runtime

How does NuGet resolve version conflicts when two packages depend on different versions of the same transitive dependency?

Intermediate
Modern NuGet uses a resolution algorithm that generally selects the lowest version that satisfies all direct and transitive constraints for older-style ranges, but with PackageReference and central package management, NuGet more commonly applies 'nearest wins' with automatic upgrade to the highest specified minimum version among conflicting requirements, and warns (NU1605) if a downgrade would otherwise occur, requiring an explicit override.
<!-- PackageA needs Newtonsoft.Json 12.0, PackageB needs 13.0 --
     NuGet resolves to 13.0 (the higher constraint) automatically -->
<ItemGroup>
  <PackageReference Include="PackageA" Version="1.0" />
  <PackageReference Include="PackageB" Version="2.0" />
</ItemGroup>
Real-world example A build fails with an NU1605 'detected package downgrade' error after a new dependency is added, forcing the developer to explicitly bump a transitive dependency's version to resolve the conflict.

Common follow-ups: What does the NU1605 warning specifically mean?;How do you force a specific version of a transitive dependency?

Assemblies & NuGet;.NET CLI SDK & Project Structure (csproj)

What is Central Package Management (CPM) in NuGet, and how does Directory.Packages.props centralize version control?

Advanced
Central Package Management lets you specify all package versions once in a repository-root Directory.Packages.props file, with individual project .csproj files referencing packages by name only (without a version), ensuring every project in a multi-project solution uses exactly the same version of any shared dependency, eliminating version drift across a large codebase.
<!-- Directory.Packages.props -->
<Project>
  <PropertyGroup><ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally></PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
</Project>

<!-- Individual .csproj: no version needed -->
<PackageReference Include="Newtonsoft.Json" />
Real-world example A monorepo with 50 projects adopts Central Package Management so bumping a security-patched package version requires editing exactly one file instead of 50 separate .csproj files.

Common follow-ups: How do you override a centrally-managed version for one specific project?;How does CPM interact with transitive dependency pinning?

.NET CLI SDK & Project Structure (csproj);CI/CD Publishing & Deployment

What is strong naming of assemblies, and why is it much less commonly required in modern .NET?

Intermediate
Strong naming signs an assembly with a public/private key pair, giving it a unique identity (name, version, culture, public key token) primarily used historically for GAC installation and preventing assembly substitution/tampering in .NET Framework. Modern .NET's side-by-side, per-application deployment model and absence of a GAC removes most of the original motivations for strong naming, though it's still occasionally required for specific interop scenarios or organizational policy.
<PropertyGroup>
  <SignAssembly>true</SignAssembly>
  <AssemblyOriginatorKeyFile>MyKey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
Real-world example A library targeting both legacy Framework consumers (who still expect strong-named assemblies for GAC compatibility) and modern .NET consumers maintains strong naming primarily for backward compatibility rather than any modern security need.

Common follow-ups: Does strong naming provide real security guarantees on its own?;When would a modern .NET project still need strong naming?

Assemblies & NuGet;.NET vs .NET Framework

How does semantic versioning apply to NuGet packages, and what do version range operators like [1.0,2.0) mean?

Advanced
NuGet packages follow SemVer (MAJOR.MINOR.PATCH), and PackageReference version strings support range syntax: a plain '1.0.3' means 'this version or higher' (minimum version, NuGet's default interpretation), while explicit interval notation like [1.0,2.0) means 'greater than or equal to 1.0, less than 2.0' (square brackets inclusive, parentheses exclusive), letting you constrain acceptable upgrade ranges precisely.
<!-- Minimum version (most common) -->
<PackageReference Include="Serilog" Version="3.1.0" />

<!-- Exact version only -->
<PackageReference Include="Serilog" Version="[3.1.0]" />

<!-- Range: >= 3.0, < 4.0 -->
<PackageReference Include="Serilog" Version="[3.0,4.0)" />
Real-world example A library author pins a range like [3.0,4.0) for a dependency known to have breaking changes at major version boundaries, protecting consuming applications from an unexpected breaking upgrade during a routine restore.

Common follow-ups: Why does NuGet default to treating a plain version number as a minimum rather than exact?;How do floating versions like 3.1.* work?

Assemblies & NuGet;.NET CLI SDK & Project Structure (csproj)

How do you create and publish your own NuGet package from a class library project?

Intermediate
Set <IsPackable>true</IsPackable> (default for class libraries) along with package metadata (PackageId, Version, Authors, Description) in the .csproj, run `dotnet pack` to produce a .nupkg file, then publish it with `dotnet nuget push` to NuGet.org or a private feed using an API key.
<PropertyGroup>
  <PackageId>MyCompany.Utilities</PackageId>
  <Version>1.2.0</Version>
  <Authors>MyCompany</Authors>
  <Description>Shared utility functions</Description>
</PropertyGroup>

dotnet pack -c Release
dotnet nuget push bin/Release/MyCompany.Utilities.1.2.0.nupkg --api-key <key> --source https://api.nuget.org/v3/index.json
Real-world example A company publishes an internal SharedValidation library to a private Azure Artifacts NuGet feed, letting every internal team consume it via a normal PackageReference instead of copying source code between repositories.

Common follow-ups: How does dotnet pack decide what files to include in the .nupkg?;What's the difference between publishing to NuGet.org versus a private feed?

.NET CLI SDK & Project Structure (csproj);CI/CD Publishing & Deployment

What is assembly loading context, and how does AssemblyLoadContext enable plugin isolation in modern .NET?

Advanced
AssemblyLoadContext (ALC) replaces .NET Framework's AppDomain for isolating loaded assemblies -- you can create a custom, collectible ALC to load a plugin's assemblies in isolation from the main application and other plugins, with the ability to unload it later (freeing memory) once the plugin is no longer needed, something AppDomains could also do but with much heavier overhead and cross-domain marshaling complexity.
var alc = new AssemblyLoadContext("PluginContext", isCollectible: true);
var assembly = alc.LoadFromAssemblyPath("/plugins/MyPlugin.dll");
var pluginType = assembly.GetType("MyPlugin.Plugin");

// Later, unload the entire plugin and its assemblies:
alc.Unload();
Real-world example A plugin-based reporting application loads each third-party report generator DLL into its own collectible AssemblyLoadContext, letting administrators update or remove a plugin at runtime without restarting the whole application.

Common follow-ups: Why is default assembly unloading not possible without a custom collectible ALC?;What are common pitfalls with type identity across different ALCs?

CLR & Runtime;.NET vs .NET Framework

What is the difference between a NuGet package's dependency group targeting different frameworks, and why do multi-targeted packages need this?

Intermediate
A single NuGet package (.nupkg) can bundle multiple sets of assemblies, each compiled for a different target framework (net472, netstandard2.0, net8.0), organized in a lib/{tfm}/ folder structure -- when a consuming project restores the package, NuGet automatically selects the best-matching assembly set for that project's own TargetFramework, letting one package serve both legacy Framework and modern .NET consumers from a single published artifact.
<!-- Library project multi-targets to produce one package supporting multiple consumers -->
<PropertyGroup>
  <TargetFrameworks>net472;netstandard2.0;net8.0</TargetFrameworks>
</PropertyGroup>

<!-- Resulting .nupkg structure:
     lib/net472/MyLib.dll
     lib/netstandard2.0/MyLib.dll
     lib/net8.0/MyLib.dll -->
Real-world example A popular open-source logging library publishes one NuGet package that automatically provides the correct assembly whether the consumer is a legacy .NET Framework 4.7.2 app or a modern .NET 8 application, without the consumer needing to think about it.

Common follow-ups: How do you write framework-conditional code within a multi-targeted project?;What happens if no matching TFM exists for the consumer's project?

.NET vs .NET Framework;.NET CLI SDK & Project Structure (csproj)

Showing 1–10 of 15