NuGetGallery
Overview
NuGetGallery is the primary web application for nuget.org. It is an ASP.NET MVC 5 / Web API 2 project targeting .NET Framework 4.7.2, hosted on IIS via an OWIN pipeline. The application handles every user-facing concern: browsing and searching packages, uploading and deleting packages via the NuGet push API, managing user accounts and organizations, rendering package detail pages, serving the legacy V2 OData feed consumed by older NuGet clients, and providing a restricted admin panel. The project is built as aLibrary assembly (OutputType=Library) deployed to IIS — the OWIN startup class (OwinStartup) is detected automatically by the Microsoft.Owin.Host.SystemWeb host. All request routing flows through this single process; background work (validation, indexing, catalog) is handled by separate job executables.
The web application operates in two modes: full mode (UI + API) and feed-only mode (
feedOnlyMode=true), in which all MVC UI routes are suppressed and only the V2 OData API is registered. Feed-only mode exists to allow separate “feed-only” deployments behind the load balancer that serve NuGet client traffic without serving browser traffic.Role in the NuGetGallery Ecosystem
Upstream: Package Authors
Authors push
.nupkg files via the V2 push API (PUT /api/v2/package). The gallery validates the upload, persists it to Azure Blob Storage in the uploads container, and enqueues a validation message via AsynchronousPackageValidationInitiator.Downstream: Validation Orchestrator
After a push, the gallery writes a
PackageValidationSet record and sends a Service Bus message. The Validation Orchestrator drives the package through validators until it is marked Available or FailedValidation.Downstream: Search / Azure Search
The gallery calls out to an external search service (Azure AI Search via
NuGet.Services.AzureSearch) for package search. The IHijackSearchServiceFactory pattern redirects OData V2 queries to the search service to avoid database fan-out.Downstream: Db2Catalog / V3 Feed
When a package is made
Available, its LastEdited timestamp is updated. The Db2Catalog job detects this change and publishes the package into the V3 NuGet protocol (registration, flat container, catalog).Request Pipeline
The OWIN pipeline is bootstrapped in this order byOwinStartup.Configuration:
ServicePointManagertuning (connection limits, TLS 1.2, Nagle disabled).- Autofac DI container composition (
AutofacConfig.UseAutofacInjection) — scans the assembly forIAutofacModuleregistrations and all controller types. - OWIN cookie authentication middleware (
CookieAuthenticationMiddleware) with sliding expiration. - External OAuth providers (AAD v2, Microsoft Account) registered via
Authenticatorsubclasses. - MVC route table (
Routes.RegisterRoutes) and Web API (WebApiConfig.Register) with OData V1/V2 endpoints. - Feature flag service wired through
NuGet.Services.FeatureFlags.
Key Files and Classes
Dependencies
Internal Project References
Key NuGet Package Dependencies
Notable Patterns and Implementation Details
Search hijacking on OData V2. Rather than letting all
FindPackagesById, Search, and GetUpdates OData queries hit SQL Server, ODataV2FeedController uses IHijackSearchServiceFactory to redirect eligible queries to the Azure Search-backed search service. The decision is logged via the internal X-NuGet-CustomQuery response header, and telemetry tracks whether each query was hijacked or fell back to the database.Property injection on MVC controllers. Unlike Web API controllers (which use constructor injection), MVC controllers in this project use Autofac property injection (
PropertiesAutowired()). This is a legacy pattern from when the project used an older DI approach; public service properties on controller classes are set by the Autofac container.Feed-only mode. When
feedOnlyMode=true is passed to Routes.RegisterRoutes, only the V2 OData routes and a stub home route (returning HTTP 200 for health probes) are registered. This allows Azure Load Balancer nodes that handle only client protocol traffic to run a leaner version of the app without the full MVC UI surface.