From f4c03a02eb6d7cae8137c0e22a587aa320b51fd1 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 29 Jun 2026 15:31:50 -0700 Subject: [PATCH 1/3] Add proposal for apps resolving a deployed shared set of dependencies --- INDEX.md | 1 + ...shared-dependencies-across-applications.md | 95 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 proposed/shared-dependencies-across-applications.md diff --git a/INDEX.md b/INDEX.md index 19aca180f..002bc8acd 100644 --- a/INDEX.md +++ b/INDEX.md @@ -110,6 +110,7 @@ Use update-index to regenerate it: | | [Readonly references in C# and IL verification.](proposed/verifiable-ref-readonly.md) | | | | [Ref returns in C# and IL verification.](proposed/verifiable-ref-returns.md) | | | | [SDK Analysis Level Property and Usage](proposed/sdk-analysis-level.md) | (PM) [Chet Husk](https://github.com/baronfel), (Engineering) [Daniel Plaisted](https://github.com/dsplaisted) | +| | [Shared dependencies across applications](proposed/shared-dependencies-across-applications.md) | | | | [Swift Interop](proposed/swift-interop.md) | [Andy Gocke](https://github.com/agocke), [Jeremy Koritzinsky](https://github.com/jkoritzinsky) | | | [Target AVX2 in R2R images](proposed/vector-instruction-set-default.md) | [Richard Lander](https://github.com/richlander) | diff --git a/proposed/shared-dependencies-across-applications.md b/proposed/shared-dependencies-across-applications.md new file mode 100644 index 000000000..af80fa02b --- /dev/null +++ b/proposed/shared-dependencies-across-applications.md @@ -0,0 +1,95 @@ +# Shared dependencies across applications + +The .NET deployment model optionally shares the runtime across apps, but offers no sharing model for other libraries. When multiple applications share many of the same dependencies, each carries its own copies, inflating the overall deployment and requiring every app to be updated to pick up a dependency change. If that common set of libraries is owned and versioned together, it is a natural set to deploy once and share. + +**Goals** +- Apps can reference the shared set at build time without deploying it into each app's output +- The shared set lives in a shared location on disk and is resolved at run time by apps that referenced it at build time +- A single deployment of the shared set is used by all the applications +- The shared set can be updated independently of the apps + +**Non-goals** +- Extension of the shared framework concept (global install, name-based framework references, framework versioning) to third parties +- Machine-wide assembly store cache +- Deployment of the applications and their shared set(s) + +## Proposed approach + +### Runtime resolution + +The host reads a `sharedDependencies` array in `runtimeconfig.json`. Each entry points at a shared set's `.deps.json`. + +`App.runtimeconfig.json`: + +```json +{ + "runtimeOptions": { + "tfm": "net11.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "11.0.0" + }, + "sharedDependencies": [ + "/opt/AppSuite.Shared/AppSuite.Shared.deps.json" + ] + } +} +``` + +- Each `sharedDependencies` entry is an absolute path to the shared set's `.deps.json`. We can relax this later if there is a specific need (for example, paths relative to the app or environment variables). +- The host merges each shared set's `deps.json` into the app's dependencies at startup. The shared set is treated as part of the app, so it resolves with the same priority as assets directly in the app's `deps.json` (that is, before frameworks). This is similar to an [additional `deps.json` via `--additional-deps`/`DOTNET_ADDITIONAL_DEPS`](https://github.com/dotnet/runtime/blob/main/docs/design/features/additional-deps.md). +- The assets in a shared set's `deps.json` are resolved relative to that `deps.json`'s folder (`/opt/AppSuite.Shared/` in the above example). The presence of `sharedDependencies` does not trigger file existence checks at startup. This differs from `--additional-deps`/`DOTNET_ADDITIONAL_DEPS`, which resolves an additional deps file's assets relative to the app directory and enables those file existence checks. + +### Developer experience + +An app can reference a shared set so it compiles against the libraries without copying them into its output, and the build records the deployed `.deps.json` in the app's `sharedDependencies`. The shared set can be a project that aggregates the libraries to be shared. + +`App.csproj` (app): + +```xml + + + Exe + net11.0 + + + + + + + + + + + + + +``` + +`AppSuite.Shared.csproj` (shared set): + +```xml + + + net11.0 + + + + + + + +``` + +- `SharedDependencyLocation` metadata on the reference turns copy-local off and emits the `sharedDependencies` entry (`/`). +- `SharedDependency` item points at a deployed `.deps.json` and emits the entry. +- Publishing the shared set produces a layout with the dependency assemblies and a `deps.json`. That layout is deployed to the shared location and the `deps.json` is pointed at by `sharedDependencies`. + +## Related + +- [dotnet/runtime#53834](https://github.com/dotnet/runtime/issues/53834) — Support deploying multiple exes as a single self-contained set +- [`--additional-deps`/`DOTNET_ADDITIONAL_DEPS`](https://github.com/dotnet/runtime/blob/main/docs/design/features/additional-deps.md) — existing support for additional deps files via command line or environment variable +- Not directly related, but in the space of configuring how dependencies can be laid out and found + - [Configure .NET install search behavior](https://learn.microsoft.com/dotnet/core/deploying#configure-net-install-search-behavior) — existing configuration for how the apphost finds the .NET install + - [dotnet/sdk#48406](https://github.com/dotnet/sdk/issues/48406) — `localPath` in `deps.json` is used for asset resolution and can be customized via `DestinationSubDirectory`: [dotnet/runtime#117682](https://github.com/dotnet/runtime/issues/117682), [dotnet/runtime#118297](https://github.com/dotnet/runtime/pull/118297), [dotnet/sdk#50120](https://github.com/dotnet/sdk/pull/50120) \ No newline at end of file From f97b5fd08771396c2c8ec2cc1d8350addabe1e36 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 6 Jul 2026 13:01:49 -0700 Subject: [PATCH 2/3] Apply suggestion from @elinor-fung --- proposed/shared-dependencies-across-applications.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposed/shared-dependencies-across-applications.md b/proposed/shared-dependencies-across-applications.md index af80fa02b..03a3dc042 100644 --- a/proposed/shared-dependencies-across-applications.md +++ b/proposed/shared-dependencies-across-applications.md @@ -36,7 +36,7 @@ The host reads a `sharedDependencies` array in `runtimeconfig.json`. Each entry } ``` -- Each `sharedDependencies` entry is an absolute path to the shared set's `.deps.json`. We can relax this later if there is a specific need (for example, paths relative to the app or environment variables). +- Each `sharedDependencies` entry is either an absolute path or relative path (based on the app's directory) to the shared set's `.deps.json`. Environment variables are not supported. - The host merges each shared set's `deps.json` into the app's dependencies at startup. The shared set is treated as part of the app, so it resolves with the same priority as assets directly in the app's `deps.json` (that is, before frameworks). This is similar to an [additional `deps.json` via `--additional-deps`/`DOTNET_ADDITIONAL_DEPS`](https://github.com/dotnet/runtime/blob/main/docs/design/features/additional-deps.md). - The assets in a shared set's `deps.json` are resolved relative to that `deps.json`'s folder (`/opt/AppSuite.Shared/` in the above example). The presence of `sharedDependencies` does not trigger file existence checks at startup. This differs from `--additional-deps`/`DOTNET_ADDITIONAL_DEPS`, which resolves an additional deps file's assets relative to the app directory and enables those file existence checks. From d750e31957afab6c977b14fedfe4dca1f640c7dc Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 28 Jul 2026 13:54:41 -0700 Subject: [PATCH 3/3] Add example with PackageReference --- proposed/shared-dependencies-across-applications.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/proposed/shared-dependencies-across-applications.md b/proposed/shared-dependencies-across-applications.md index 03a3dc042..0d8ab948f 100644 --- a/proposed/shared-dependencies-across-applications.md +++ b/proposed/shared-dependencies-across-applications.md @@ -42,7 +42,7 @@ The host reads a `sharedDependencies` array in `runtimeconfig.json`. Each entry ### Developer experience -An app can reference a shared set so it compiles against the libraries without copying them into its output, and the build records the deployed `.deps.json` in the app's `sharedDependencies`. The shared set can be a project that aggregates the libraries to be shared. +An app references a shared set so it compiles against the libraries without deploying them, and the build records the deployed `.deps.json` in the app's `sharedDependencies`. The shared set can be a project or package that aggregates the libraries to be shared. `App.csproj` (app): @@ -59,10 +59,15 @@ An app can reference a shared set so it compiles against the libraries without c SharedDependencyLocation="/opt/AppSuite.Shared/" /> - + + + + ``` @@ -86,9 +91,12 @@ An app can reference a shared set so it compiles against the libraries without c - `SharedDependency` item points at a deployed `.deps.json` and emits the entry. - Publishing the shared set produces a layout with the dependency assemblies and a `deps.json`. That layout is deployed to the shared location and the `deps.json` is pointed at by `sharedDependencies`. +This relies on existing or future functionality for marking a reference as external — compiled against but not deployed with the app. `Private="false"` (copy-local off) on a project reference exists today. `HostProvided="true"` on a package reference would come from a future NuGet feature for compile-only assets and audit ownership transfer to whoever deploys the set. That NuGet design is still in progress and not finalized. Support for both need not land together — project references alone are already valuable. + ## Related - [dotnet/runtime#53834](https://github.com/dotnet/runtime/issues/53834) — Support deploying multiple exes as a single self-contained set +- [dotnet/runtime#71282](https://github.com/dotnet/runtime/issues/71282) — Locally shared deployment - [`--additional-deps`/`DOTNET_ADDITIONAL_DEPS`](https://github.com/dotnet/runtime/blob/main/docs/design/features/additional-deps.md) — existing support for additional deps files via command line or environment variable - Not directly related, but in the space of configuring how dependencies can be laid out and found - [Configure .NET install search behavior](https://learn.microsoft.com/dotnet/core/deploying#configure-net-install-search-behavior) — existing configuration for how the apphost finds the .NET install