Skip to main content

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 a Library 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 by OwinStartup.Configuration:
  1. ServicePointManager tuning (connection limits, TLS 1.2, Nagle disabled).
  2. Autofac DI container composition (AutofacConfig.UseAutofacInjection) — scans the assembly for IAutofacModule registrations and all controller types.
  3. OWIN cookie authentication middleware (CookieAuthenticationMiddleware) with sliding expiration.
  4. External OAuth providers (AAD v2, Microsoft Account) registered via Authenticator subclasses.
  5. MVC route table (Routes.RegisterRoutes) and Web API (WebApiConfig.Register) with OData V1/V2 endpoints.
  6. 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.
Migrations are disabled at runtime. EntitiesContext calls Database.SetInitializer<EntitiesContext>(null) in its static constructor. Schema changes are applied by a separate DatabaseMigrationTools executable — never by the running web application. Running EF migrations against a live production database from within the app would be unsafe at scale.
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.
OWIN on .NET Framework 4.7.2. The application uses Microsoft.Owin.Host.SystemWeb to run the OWIN pipeline inside an IIS/ASP.NET integrated pipeline — not Kestrel. This means the host is bound to Classic System.Web infrastructure (HttpContext, HttpResponse) and cannot be moved to ASP.NET Core without significant rearchitecting.
Typosquatting protection. TyposquattingService uses a cached list of existing package IDs (ITyposquattingCheckListCacheService) and a confusable-character mapping to block uploads that would appear visually similar to popular packages. The check runs synchronously during the upload validation phase before the package is committed to the database.