interactive icon indicating copy to clipboard operation
interactive copied to clipboard

Global pre-installation of NuGet packages for Polyglot Notebooks

Open jamesmcroft opened this issue 1 year ago • 2 comments

Is your feature request related to a problem? Please describe.

Unlike Python Notebooks, where packages installed in the environment are automatically available (potentially via a requirements.txt file, Polyglot Notebooks require an explicit magic command (e.g. #r "nuget: Azure.Identity, 1.13.2") to load a NuGet package. Although it’s possible to pre-install packages (using a runtime store, or global NuGet cache), these aren’t available to the interactive session’s context. This isolation—while excellent for reproducibility and avoiding version conflicts—adds extra boilerplate and complexity that hinders a smooth developer experience.

Describe the solution you'd like

I would like Polyglot Notebooks to support loading NuGet packages from a global/local source. NuGet packages that are installed globally in the development environment (for example, via a devcontainer setup or a pre-populated runtime store) would automatically be referenced in every notebook session without requiring explicit #r "nuget: ..." commands. This functionality should ensure the environment’s packages are available by default, thereby reducing repetitive code and simplifying dependency management across notebooks.

Describe alternatives you've considered

Currently, the only reliable method to load NuGet packages in notebooks is to add an explicit magic command in each notebook.

I approached pre‑installing packages in a global NuGet cache and using a runtime store, but they do not trigger automatic assembly loading in .NET Interactive sessions. The attempt followed these steps:

NuGet Cache Option

  1. Create a dummy .csproj file which includes the necessary NuGet packages to install in the environment, mimicking Python's requirements.txt.
  2. Create a nuget.config at the root of the repo with the following configuration:
<configuration>
  <config>
    <add key="globalPackagesFolder" value="/workspaces/<repo>/packages" />
  </config>
</configuration>
  1. Run dotnet restore

Unfortunately, the packages installed here are ignored by the repo's Notebooks.

.NET Runtime Package Store

As an alternative, attempted to explore an approach using package stores as follows:

  1. Create a dummy .csproj file which includes the necessary NuGet packages to install in the environment, mimicking Python's requirements.txt.
  2. Run dotnet store --manifest requirements.csproj --framework net9.0 --runtime linux-x64 --skip-optimization --output /workspaces/<repo>/share/dotnet/store
  3. Set the DOTNET_SHARED_STORE to the path (as described in the runtime docs - https://github.com/dotnet/runtime/blob/main/docs/design/features/DotNetCore-SharedPackageStore.md)

Again, unfortunately, this also doesn't load the packages into a repo's Notebooks.

Example dummy .csproj file

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>net8.0;net9.0</TargetFrameworks>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Azure.Identity" Version="1.13.2" />
        <PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
        <PackageReference Include="DotNetEnv" Version="3.1.1" />
    </ItemGroup>
</Project>

jamesmcroft avatar Mar 02 '25 21:03 jamesmcroft

While not 100% ideal, a cleaner workaround is to create a Notebook file which imports all the necessary NuGet packages and reference this via a #!import command.

However, I want to be able to appropriately maintain the packages and their versions in GitHub repos using dependabot, like what can be achieved with Python's requirements.txt for Jupyter Notebooks.

jamesmcroft avatar Mar 02 '25 21:03 jamesmcroft

This is a compelling idea and your mention of using a .csproj reminds me of #890.

jonsequitur avatar Mar 03 '25 19:03 jonsequitur