# .NET and NuGet

> Restore NuGet packages from Telesphorepo with dotnet, and what is different when you publish them.

Source: https://docs.telesphorepo.com/nuget/

This page sets up dotnet to restore packages from Telesphorepo. To publish a package, see [Publish from a project](/publish-from-a-project/), under Publish your packages; what is different for NuGet is under [Publish to this repository](#publish-to-this-repository).

An admin first makes a repository with the format **NuGet** (see [Make a repository](/repositories-and-access/#make-a-repository)). The examples use the server `repo.example.com` and a repository named `dotnet`, so the package source is this:

```text
https://repo.example.com/nuget/dotnet/index.json
```

dotnet, nuget.exe and Visual Studio read it. Put your own values in the blocks below. The **Use this repository** tab of the repository shows the same blocks with your values.

## Restore packages

1. Make a read token.

   #### Anyone can download

   Skip this step. Anyone can download.

   #### Only signed-in people

   **Settings** › **Tokens** › **New read token**. Type a name, then click **Create token**.

2. Put `nuget.config` next to the solution. dotnet reads it for every project below it.

   #### Anyone can download

   ```xml title="nuget.config"
   <?xml version="1.0" encoding="utf-8"?>
   <configuration>
     <packageSources>
       <add key="dotnet" value="https://repo.example.com/nuget/dotnet/index.json" />
     </packageSources>
   </configuration>
   ```

   #### Only signed-in people

   ```xml title="nuget.config"
   <?xml version="1.0" encoding="utf-8"?>
   <configuration>
     <packageSources>
       <add key="dotnet" value="https://repo.example.com/nuget/dotnet/index.json" />
     </packageSources>
     <packageSourceCredentials>
       <dotnet>
         <add key="Username" value="YOUR_USERNAME" />
         <add key="ClearTextPassword" value="YOUR_READ_TOKEN" />
       </dotnet>
     </packageSourceCredentials>
   </configuration>
   ```

   The file holds your token. Before you commit it, write `%NUGET_USERNAME%` and `%NUGET_TOKEN%` in place of the values, and set those variables on each computer and in CI.

   #### nuget.org packages too

   To restore every package through the repository, add `<clear />` as the first line in `<packageSources>`. dotnet then skips nuget.org.

3. Add a package.

   ```sh
   dotnet add package Contoso.Core --version 1.2.0
   ```

   dotnet writes the line into the project file:

   ```xml title="App.csproj"
   <ItemGroup>
     <PackageReference Include="Contoso.Core" Version="1.2.0" />
   </ItemGroup>
   ```

Done when `dotnet restore` ends with no error.

Add the source for your user, with no nuget.config in the project

#### Anyone can download

```sh
dotnet nuget add source https://repo.example.com/nuget/dotnet/index.json --name dotnet
```

#### Only signed-in people

Paste the token at the hidden prompt.

```sh
printf 'Read token: '; read -rs READ_TOKEN; echo
dotnet nuget add source https://repo.example.com/nuget/dotnet/index.json --name dotnet \
  --username YOUR_USERNAME --password "$READ_TOKEN" --store-password-in-clear-text
```

dotnet adds the source to the `nuget.config` of your user.

## Your own packages

A hosted repository holds your own packages only. dotnet still restores the packages of nuget.org from nuget.org. To restore every package through one source, ask your server admin for a group of your repository and a proxy of nuget.org.

## nuget.org packages too

A group asks its members in order. The first member that has a package id owns it, and the group serves every version of that id from that member only. So a package on nuget.org with the id of your private package cannot take its place, even with a higher version. Your admin puts your hosted repository before the proxy. A proxy stores the packages of nuget.org unchanged, so they keep the signatures of their authors and of nuget.org.

## Publish to this repository

Publish as in [Publish from a project](/publish-from-a-project/): run the setup line in the folder that holds the `.sln`, `.slnx`, `.csproj` or `.fsproj` file, commit `telesphorepo.toml`, then run `telesphorepo publish`.

Done when the CLI prints `Pushed` for each package, for example `Pushed Contoso.Core.1.2.0.nupkg to dotnet`.

The CLI runs `dotnet pack -c Release` into a temporary folder, then pushes each package that it wrote, with a publish token for this one repository. It skips `.symbols.nupkg` files. To push packages that you built, name them: `telesphorepo publish bin/Release/*.nupkg`. The CLI then builds nothing. The server stores the bytes of a package unchanged, so a signed package keeps its signature.

A version that the repository has already answers `409`, also with the same bytes. Raise the version.

Publish with dotnet nuget push

Make a publish token in **Settings** › **Tokens** › **New publish token**: choose the repository, then confirm with your second factor. The token works for 15 minutes. dotnet takes it as the API key:

```sh
printf 'Publish token: '; read -rs TOKEN; echo
dotnet nuget push Contoso.Core.1.2.0.nupkg --source https://repo.example.com/nuget/dotnet/index.json --api-key "$TOKEN"
```

dotnet takes the API key only as an argument, so the token shows in the process list while the push runs. A password or a read token cannot push.

### The CI file for .NET

[Publish from CI](/publish-from-ci/) has the steps. When you choose **GitHub Actions** at setup, the CLI writes this file:

```yaml title=".github/workflows/publish.yml"
on:
  push:
    branches: ["main"]

permissions:
  id-token: write
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-dotnet@v5
        with:
          dotnet-version: 10.0.x
      - run: curl -fsSL https://repo.example.com/install.sh | sh
      - run: telesphorepo publish
```

The identity token publishes only. If the restore reads a private repository, keep a read token in a CI secret, and set `NUGET_USERNAME` and `NUGET_TOKEN`. For Jenkins, see [Publish from CI](/publish-from-ci/).

## If something goes wrong

dotnet refuses an `http://` source

Add `allowInsecureConnections="true"` to the `<add>` line of the source. For real use, serve the server over HTTPS. See [Serve over HTTPS](/run-the-server/#serve-over-https).

401 when you restore

The repository is for signed-in people only. Check `packageSourceCredentials`: the element name must be the key of the source, here `<dotnet>`. A key that starts with a digit is written with `_x003` and the digit, as in `<_x0031_api>` for the key `1api`.

dotnet cannot find a package of nuget.org

With `<clear />`, every package comes through the repository. Ask your server admin for a group with a proxy of nuget.org, or remove `<clear />`.

A group serves your private package, not the one on nuget.org

The first member that has an id owns it. Rename your package, or ask your admin to change the order of the members.

409 when you publish

That version is on the server. Raise the version. With `dotnet nuget push`, add `--skip-duplicate` to skip the packages that are there already.

`dotnet pack wrote no package`

A project packs when it is packable. Add `<IsPackable>true</IsPackable>` to the project file. A test project does not pack.

The CLI says that dotnet is not on the PATH

Install the .NET SDK.

You want to hide a version

Run `dotnet nuget delete Contoso.Core 1.2.0 --source https://repo.example.com/nuget/dotnet/index.json` with a publish token as the API key. The server unlists the version. dotnet still restores it by its exact version.
