¿Alguna vez has entrado a un proyecto Legacy (o incluso uno nuevo mal configurado), intentas compilar y tu consola se tiñe de rojo con errores tipo The type or namespace name 'X' could not be found? 😵 O peor aún, ¿te ha tocado ese escenario donde el proyecto busca una DLL en una carpeta de red Z:\Librerias que solo existía en la máquina del desarrollador que renunció hace dos años?
Si te ha pasado, sabes la frustración de perder horas (o días) solo intentando levantar el entorno. A menudo, el problema no es el código C#, es la gestión de dependencias. Hoy vamos a arreglar esto de raíz, entendiendo cómo consumir librerías de forma profesional, segura y escalable.
¿Qué es realmente NuGet?
Imagina que NuGet es el Amazon o Mercado Libre de .NET. Tú no fabricas cada tornillo de tu mueble; los pides a la tienda.
- El Package: Es el producto que compras (Newtonsoft.Json, EntityFramework).
- El Source (Feed): Es el almacén o la tienda donde se guardan los paquetes.
¿A dónde van mis paquetes?
Muchos desarrolladores creen que cuando ejecutan dotnet restore, las DLLs "mágicamente" aparecen en su proyecto. Entender el flujo real es vital para saber qué está pasando por detrás:
-
Request: Tu proyecto (
.csproj) pideNewtonsoft.Jsonv13.0.1. - Restore: NuGet busca en los Sources configurados.
-
Global Packages Folder: Aquí está el secreto. NuGet descarga y descomprime el paquete en una carpeta global de tu usuario (generalmente
%userprofile%\.nuget\packagesen Windows o~/.nuget/packagesen Linux/Mac). No se guardan dentro de tu proyecto. - Build: Cuando compilas, .NET lee las DLLs de esa carpeta global y las copia a tu carpeta bin/Debug o bin/Release.
¿Por qué importa esto? Porque optimiza el espacio. Si tienes 10 proyectos usando la misma librería, solo se descarga una vez en tu disco duro.
La jerarquía de configuración
Antes de escribir una sola línea de configuración, debes entender cómo "piensa" NuGet. Cuando ejecutas un restore, no solo mira tu proyecto. NuGet combina configuraciones en cascada siguiendo una jerarquía estricta:
- Nivel Máquina: A menudo este archivo ni siquiera existe físicamente o está vacío, a menos que un administrador de sistemas lo haya puesto ahí.
-
Nivel Usuario: Este es el más común (
%appdata%\NuGet\NuGet.Config) y suele acumular mucha "basura digital" con el tiempo. - Nivel Directorio (Recursivo): ¡Aquí está la trampa! NuGet busca en la carpeta de tu solución... pero si no encuentra lo que busca, sube a la carpeta padre, y luego a la del abuelo, hasta llegar a la raíz del disco.
El origen del "En mi máquina funciona" 🤷♂️
Aquí nace el famoso meme. Imagina que tú tienes configurado un feed privado en tu Nivel Usuario porque trabajas en varios proyectos de la empresa. Creas un proyecto nuevo y compila perfecto. Tu compañero clona el repositorio, intenta compilar y... error.
¿Por qué? Porque tu proyecto está dependiendo de una configuración "invisible" que vive solo en tu usuario. Para tu compañero, ese feed no existe.
¿Cómo detecto esto? No adivines. Sitúate en la carpeta de tu solución y ejecuta el siguiente comando:
dotnet nuget list source
Este comando te mostrará la lista final y combinada de todos los orígenes que NuGet está usando realmente en esa carpeta. Si ves rutas que no reconoces o servidores apagados, es culpa de la herencia.
NuGet.config
¿Cómo rompemos esa cadena de herencia tóxica y arreglamos el proyecto para todos? Creando un archivo NuGet.config explícito en la raíz de tu solución.
Aquí tienes una configuración que cubre los escenarios reales:
<configuration>
<packageSources>
<!-- ¡IMPORTANTE! <clear/> elimina toda la "basura" heredada del usuario o máquina -->
<clear />
<!-- 1. El estándar público -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- 2. Nube Privada (GitHub Packages, Azure, AWS) -->
<!-- Ideal para equipos modernos y CI/CD -->
<add key="GitHubFeed" value="https://nuget.pkg.github.com/mi-empresa/index.json" />
<!-- 3. Servidor NuGet Local (BaGet o similar) -->
<add key="BadGetFeed" value="http://servidor-interno:5555/v3/index.json" />
<!-- 4. Carpeta Local en Servidor On-Premise -->
<add key="OnPremiseFeed" value="./LibreriasAntiguas" />
</packageSources>
<!-- Puedes deshabilitar fuentes temporalmente sin borrar la línea -->
<disabledPackageSources>
<add key="OnPremiseFeed" value="true" />
</disabledPackageSources>
<packageSourceCredentials>
<!-- Autenticación Segura para feeds privados (Usa variables de entorno) -->
<GitHubFeed>
<add key="Username" value="DevUser" />
<add key="ClearTextPassword" value="%GITHUB_TOKEN%" />
</GitHubFeed>
</packageSourceCredentials>
</configuration>
Beneficios de configurar esto:
- 🛡 Aislamiento: Con
<clear />, proteges tu proyecto de configuraciones globales rotas. - 🛠 Independencia: Si un dev nuevo entra, solo hace
git cloneydotnet restore. No necesita configurar nada manual. - 🔄 CI/CD Friendly: Tus Pipelines sabrán exactamente dónde buscar sin pasos extraños.
El caos de la prioridad
Aquí es donde muchos desarrolladores fallan. Si tienes configurado nuget.org y GitHubFeed, y ambos tienen un package llamado Newtonsoft.Json... ¿cuál se descarga?
NuGet actua "al primero que responda". Esto es peligroso por dos razones:
- Rendimiento: NuGet pierde tiempo buscando tu package privado en la tienda pública.
-
Seguridad: Si un atacante sube un paquete malicioso a
nuget.orgcon el mismo nombre que tu paquete privado interno (ej:MiBanco.Core), ¡tu proyecto podría descargar el package del atacante sin darte cuenta! 🚨
Para solucionar el caos de prioridad y asegurar qué bajamos, tenemos dos herramientas clave:
1. Package Source Mapping
Es básicamente decirle a NuGet: "Los paquetes de Microsoft búscalos en la tienda pública, y los paquetes de mi empresa SOLO búscalos en mis servidores".
<configuration>
<!-- ... sección packageSources definida arriba ... -->
<!-- AQUÍ ESTÁ LA MAGIA -->
<packageSourceMapping>
<!-- Regla 1: Mis librerías Core van a GitHub Packages -->
<packageSource key="GitHubFeed">
<package pattern="MyCompany.Core.*" />
<package pattern="MyCompany.Auth.*" />
</packageSource>
<!-- Regla 2: Librerías internas van al Server NuGet Privado -->
<packageSource key="BadGetFeed">
<package pattern="InternalTools.*" />
</packageSource>
<!-- Regla 3: Componentes viejos van a la carpeta local -->
<packageSource key="OnPremiseFeed">
<package pattern="OldComponent.WinForms.*" />
</packageSource>
<!-- Regla 4: Todo lo demás (Microsoft, System, etc.), búscalo en nuget.org -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
2. Auditoría de vulnerabilidades
A veces descargas el paquete correcto, pero tiene agujeros de seguridad conocidos. No necesitas herramientas caras; .NET lo trae nativo.
Ejecuta esto regularmente o en tu CI/CD:
dotnet list package --vulnerable
Te dirá qué paquetes tienen riesgos (Crítico, alto o moderado) y a qué versión segura actualizar.
Central Package Management (CPM)
Si trabajas en una solución con muchos servicios, seguro te ha pasado esto:
- El Proyecto A usa
Newtonsoft.Jsonv11. - El Proyecto B usa
Newtonsoft.Jsonv13. - El Proyecto C usa
Newtonsoft.Jsonv9.
¡Es un caos de versiones! 🤯
Para solucionar esto en proyectos modernos, usamos Central Package Management (CPM). En lugar de definir la versión en cada .csproj, las centralizamos.
Paso 1: Crear archivo Directory.Packages.props en la raíz
<Project>
<PropertyGroup>
<!-- Activar CPM -->
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<!-- Aquí defines la versión UNA SOLA VEZ para toda la solución -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
</ItemGroup>
</Project>
Paso 2: Limpiar tus .csproj
En tus proyectos individuales, ya no pones la versión, solo el nombre:
<!-- En .csproj -->
<ItemGroup>
<!-- Sin versión porque ya lo toma de Directory.Packages.props -->
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
¿Cómo aplico los cambios?
Una vez que has creado o ajustado tu archivo NuGet.config con los sources y el mapping, ve a tu terminal y ejecuta:
# Limpia cachés locales para asegurar que las reglas nuevas apliquen
dotnet nuget locals all --clear
# Restaura usando la nueva configuración
dotnet restore
¿Por qué deberías dominar esto?
- Resurrección de Proyectos: Puedes levantar proyectos Legacy en minutos mapeando los source que corresponde.
- Seguridad Empresarial: Proteges a tu organización de ataques de cadena de suministro y vulnerabilidades conocidas.
- Arquitectura Limpia: Con CPM, mantienes tus dependencias ordenadas y actualizadas sin esfuerzo.
No dejes que las dependencias te controlen a ti. ¡Toma el control de tus paquetes!
¡Happy coding! 🚀






Top comments (0)