NuGet e la debug-experience

Che cosa sia NuGet è ormai noto a tutti, ma non tutte le sue potenzialità sono conosciute.

Una cosa di cui sento parlare troppo poco (eufemismo per dire mai) è la possibilità, con pochi semplici comandi, di “pushare”, oltre al tradizionale pacchetto di nuget, anche i simboli di debug delle dll corrispondenti, rendendo la debug-experience degli utenti del package di un livello superiore.

Vediamo i semplici passi da seguire:

Creiamo un progetto di tipo ‘class library’ e chiamamolo StringUtils. Aggiungiamo un extension method per la classe string (giusto per avere del semplice codice da pacchettizzare con nuget)

public static class StringExtensionMethods
{
    public static String ToCamelCase(this String current)
    {
        if (String.IsNullOrEmpty(current)) return current;

    var result = new StringBuilder();
    for (var i=0; i<current.Length; i++)
    {
        if (i % 2 == 0)
            result.Append(current[i].ToString().ToUpper());
        else
        result.Append(current[i].ToString().ToLower());
    }
    return result.ToString();
    }
}

Passiamo ora alla console e creiamo per prima cosa i metadati da associare al pacchetto di nuget con il comando:

nuget spec

Se il precedente comando è eseguito nella stessa directory in cui è presente il file di progetto (*.csproj), nuget predispone i matadati, leggendo alcune informazioni dal file AssemblyInfo.cs del progetto stesso. La precedente operazioni dovrebbe avere generato un file StringUtils.nuspec simile a questo (da completare manualmente in alcune sue voci):

<package>
  <metadata>
    <id>StringUtils</id>
    <version>1.4</version>
    <title>StringUtils</title>
    <authors>melkio</authors>
    <owners>CodicePlastico srl</owners>
    <requirelicenseacceptance>false</requirelicenseacceptance>
    <description>
        Semplice classe di utility per le stringhe
    </description>
    <releasenotes></releasenotes>
    <copyright>Copyright ©CodicePlastico srl  2012</copyright>
    <tags>Utils</tags>
  </metadata>
</package>

Perfetto! Ora siamo pronti a generare il package vero e proprio:

nuget pack StringUtils.csproj -Symbol

Attempting to build package from 'StringUtils.csproj'.
Packing files from '...\StringUtils\bin\Debug'.
Using 'StringUtils.nuspec' for metadata.
Successfully created package '...\StringUtils.1.4.nupkg'.

Attempting to build symbols package for 'StringUtils.csproj'.
Packing files from '...\StringUtils\bin\Debug'.
Using 'StringUtils.nuspec' for metadata.
Successfully created package '...\StringUtils.1.4.symbols.nupkg'.

Notiamo nel comando precedente due cose essenziali: 1) il package è creato a partire dal file di progetto (.csproj) e non da quello con i metadati (.nuspec) 2) è stata aggiunta l’opzione ‘Symbol’, che istruisce nuget alla creazione anche di un package con i simboli di debug

Se tutto è andato a buon fine dovremmo trovare due package: StringUtils.1.4.nupkg e StringUtils.1.4.symbols.nupkg

E’ arrivato il momento di “pushare” i package sui rispettivi repository. Niente di più facile! Per prima cosa, se ancora non l’abbiamo fatto, impostiamo l’apikey associata al nostro utente nuget, tramite il comando:

nuget setApiKey AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEE

The API Key 'AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEE' was saved 
for the NuGet gallery (https://www.nuget.org) and the symbol 
server (http://nuget.gw.symbolsource.org/Public/NuGet).

…e poi…”push”

nuget push StringUtils.1.4.nupkg

Pushing StringUtils 1.4 to the NuGet gallery (https://www.nuget.org)...
Your package was pushed.
Pushing StringUtils 1.4 to the symbol server (http://nuget.gw.symbolsource.org/Public/NuGet)...
Your package was pushed.

L’applicazione console di nuget si accorge della presenza di un symbols-package e, oltre all’upload del tradizionale package sul repository di nuget, si occupa dell’upload del package con i simboli sul repository pubblico di symbolsource.

Come possiamo notare, non abbiamo dovuto fare nulla per abilitare la scrittura sul repository dei simboli. Questo perché, tramite l’apikey impostata in precedenza, symbolsource determina l’ownership del package e ne conferma o meno l’upload.

NOTA: A causa di un problema con la nuova versione dell’applicazione console di nuget (versione 1.6) della gallery di NuGet potrebbero verificarsi problemi nella verifica della ownership del package, impedendo l’upload sul repository dei simboli, generando un errore simile al seguente:

“Failed to process request. ‘Failed to verify permissions for upload: Project NuGet/StringUtils not found or inaccessible for Public/melkio. See http://www.symbolsource.org/Public/Home/Help for possible reasons. Fiddler may help diagnosing this error if your client discards attached detailed information.’. The remote server returned an error: (418) Failed to verify permissions for upload: Project NuGet/StringUtils not found or inaccessible for Public/melkio. See http://www.symbolsource.org/Public/Home/Help for possible reasons. Fiddler may help diagnosing this error if your client discards attached detailed information.”

Il problema è documentato qui e l’unico modo che, per ora, ho trovato per bypassare il problema è stato quello di scrivere sul forum di symbolsource, richiedendo l’abilitazione manuale della ownership.

A questo punto, chi utilizza il nostro package, configurando opportunamente VisualStudio come descritto qui avrà la possibilità di sfruttare anche i simboli di debug e, quindi, la possibilità di navigare nel nostro codice.

E allora, come direbbe il “mitico” Marzullo, la domanda sorge spontanea: perché se il “costo” di tale feature è praticamente nullo (fa tutto la console di nuget), non tutti i package presenti sul repository ufficiale di nuget, non hanno il loro corrispettivo in symbolsource e rendono la mia (e la vostra) debug-experience molto complicata, se non impossibile?