Compartir a través de



Julio de 2016

Volumen 31, número 7

Essential .NET: Visual Studio 2015 con herramientas de .NET Core

Por Mark Michaelis

Mark Michaelis.NET Core RC2 por fin está aquí, y en esta ocasión se trata de una verdadera "versión candidata para lanzamiento", en lugar de una beta de RC1 disfrazada de versión candidata para lanzamiento (si es que llega a eso, teniendo en cuenta todos los cambios que se produjeron después de su publicación). Gran parte del enfoque de desarrollo y la expectación en torno a .NET Core están por supuesto relacionados con sus funcionalidades multiplataforma. Este enfoque en la compatibilidad con Linux y Mac OS X ha llevado no solo a una nueva API de .NET, sino también a un tiempo de ejecución que la acompaña e incluso a un conjunto de herramientas. Las herramientas como DOTNET.EXE (anteriormente conocida como DNX, DNVM y DNU), por no hablar de Visual Studio Code, tienen el objetivo de dar a los desarrolladores de productos distintos a Microsoft la oportunidad de aprovechar .NET y, lo que es más, una experiencia para desarrolladores de primer nivel.

Todo esto es estupendo (y diría más, asombroso), pero ¿qué sucede con los desarrolladores de Microsoft veteranos? ¿Cómo continúan el desarrollo en Windows y Visual Studio con proyectos de .NET Core? En este artículo, hablaré sobre los distintos tipos de proyectos de .NET Core y explicaré los detalles de los nuevos tipos de archivos y sus funciones. También profundizaré en cómo la nueva estructura de proyectos admite la depuración en paralelo de los paquetes NuGet de código abierto a los que quiera hacer referencia, y en cómo puede depurar paso a paso por instrucciones el código fuente de dichos proyectos.

Introducción

Antes de poder comenzar a disfrutar de .NET Core RC2, obviamente querrá actualizar sus herramientas (en este caso Visual Studio 2015) para admitir la nueva plataforma. En esencia, esto implica realizar dos pasos:

  1. La descarga de .NET Core Tooling Preview 1 para Visual Studio 2015 de la página microsoft.com/net/core#windows (donde también encontrará instrucciones).
  2. La instalación del administrador de paquetes NuGet de la página bit.ly/27Rmeaj.

Supongo que ya tiene instalado Visual Studio 2015, pero si no es así, Visual Studio Community Edition está disponible de forma gratuita en visualstudio.com.

Nuevos tipos de proyecto

Cuando se hayan instalado todas las herramientas de Visual Studio, puede usar el asistente para nuevos proyectos a fin de crear un proyecto (consulte la Figura 1).

Plantillas de proyectos de .NET Core en Visual Studio
Figura 1. Plantillas de proyectos de .NET Core en Visual Studio

Como puede observar, existen cuatro tipos de proyectos (uno aparece dos veces porque se encuentra en las carpetas Visual C#\Web y Visual C#\.NET Core).

Obviamente, cada tipo de proyecto genera un conjunto de archivos distinto, como se muestra en la Figura 2.

Figura 2. Archivos incluidos en cada tipo de proyecto de Visual Studio

Nombre del archivo Biblioteca de clases Aplicación de consola Aplicación web de ASP.NET Core (.NET Core) Aplicación web de ASP.NET Core (.NET Framework)
App.config       X
Properties\AssemblyInfo.cs X X    
Class1.cs X      
Global.json X X X X
Properties\launchSettings.json     X X
Program.cs   X X X
Project.json X X X X
Project.lock.json X X X X
Project_Readme.html     X X
<Proyecto>.xproj     X X
<Proyecto>.xproj.user     X X
Startup.cs     X X
Web.config     X X

App.config es un archivo de configuración similar al tradicional <nombreaplicación>.config, que se usa desde .NET Framework 1.0. En el código siguiente se muestra el archivo predeterminado, que identifica si se debe usar la recolección de elementos no utilizados basada en servidor o la recolección de elementos no utilizados de tipo cliente o estación de trabajo (consulte bit.ly/22nm32o para más información):

<configuration>
  <runtime>
    <gcServer enabled="true"/>
   </runtime>
</configuration>

AssemblyInfo.cs identifica los datos del ensamblador, como la configuración, la empresa, el producto y la marca comercial. Se trata del archivo AssemblyInfo.cs estándar que ha formado parte de los proyectos .NET de Visual Studio desde que .NET se publicó por primera vez en 2000.

Class1.cs es un archivo de clases de C# de esqueleto para la clase Class1 e incluye su constructor predeterminado.

Global.json se genera automáticamente si selecciona "Crear un directorio para la solución" cuando se crea el primer proyecto de .NET Core. Como se detallará más tarde en este artículo, el nodo del proyecto identifica ubicaciones adicionales para el código fuente durante la depuración.

LaunchSettings.json identifica las distintas opciones de configuración de hospedaje web, incluida una dirección URL de la aplicación para depuración; un host de IIS (como IIS Express) si lo hay; variables de entorno que se deban establecer antes del inicio que, por ejemplo, la configuración de .NET Core use para identificar el entorno (desarrollo, pruebas o producción); y SSL y autenticación. Los cambios realizados en la pestaña Depurar de la ventana Propiedades de proyecto de Visual Studio ofrecen una interfaz de usuario para modificar el archivo launchSettings.json, como se muestra en la Figura 3.

Pestaña Depurar de la ventana Propiedades de proyecto de Visual Studio
Figura 3. Pestaña Depurar de la ventana Propiedades de proyecto de Visual Studio

En la Figura 4 se muestra un archivo launchSettings.json de ejemplo.

Figura 4. Archivo launchSettings.json de ejemplo

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:43799/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication1NetFramework": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Project.json es un nuevo archivo de proyecto con una funcionalidad que se solapa, en gran parte, con la del archivo *.*PROJ. Identifica cosas como referencias de proyectos, opciones de compilación como el número de versión, e identifica la plataforma en la que se compilará (por ejemplo, si es .NET Core o .NET Framework). Más adelante hablaremos sobre esto.

Project.lock.json almacena una lista de los archivos (normalmente referencias NuGet) necesarios para la compilación. Incluye números de versión de paquetes concretos, a diferencia del archivo project.json, que admite comodines. Sin project.lock.json, se producirá una restauración total de paquetes. Project.lock.json incluye un gráfico de paquetes junto con otros datos relacionados con paquetes que se han descargado de forma local (restaurados). Normalmente, este archivo no se inserta en el repositorio y, cuando no existe, se vuelve a crear mediante la ejecución de una restauración de paquetes NuGet. El archivo se muestra como un elemento secundario de project.json dentro de Visual Studio.

ClassLibrary.xproj es el archivo MSBuild que, sin necesidad de configuración, define lo que ocurrirá cuando compile el proyecto. La última versión importa Microsoft.DotNet.targets, que define las tareas de compilación que aprovechan el nuevo comando DotNet.exe. A diferencia de los archivos proj de MSBuild anteriores, los archivos xproj son increíblemente pequeños, ya que gran parte de la información se ha movido (temporalmente) a project.json.

ClassLibrary.xproj.user reemplaza el archivo Class­Library.xproj y proporciona propiedades MSBuild adicionales como la configuración específica de la depuración del usuario local (por ejemplo los puertos). Normalmente este archivo no se inserta en el repositorio porque es específico del usuario y no es visible desde dentro de Visual Studio.

Program.cs define una clase Program que incluye la definición del punto de entrada Main de la aplicación, incluso de las aplicaciones web.

Web.config ofrece una configuración mínima para IIS, le indica dónde puede encontrar el proceso de host web y configura que todo el tráfico se redirija a este proceso, como se muestra en el código siguiente:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule"
        resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%"    
      stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout"
      forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>

Observe que web.config ya no contiene configuración de la aplicación, que se ha movido a los archivos de configuración que carga Microsoft.Extensions.Configuration como indiqué en mi artículo de febrero de 2016, "Configuración en .NET Core" (bit.ly/1OoqmkJ).

Tenga en cuenta que en todos los tipos de proyecto de .NET Core creados mediante Visual Studio, si selecciona la opción "Crear un directorio para la solución", cuando se cree un nuevo proyecto se colocará todo el código fuente en un subdirectorio de la solución src. Además, se espera que los proyectos de prueba se coloquen en un directorio de prueba junto a src (aunque esto no sucederá de manera predeterminada en la versión .NET Core Tooling Preview 1 para Visual Studio 2015). Otros directorios posibles que se podrían considerar serían para cosas como compilaciones y documentaciones (le confieso que prefiero conservar mis proyectos de prueba junto con el proyecto de destino que están probando en lugar de en un árbol completamente separado, pero no es esto lo que Microsoft ha seleccionado para la estructura predeterminada de la solución, y la experiencia me dice que adopte el comportamiento predeterminado siempre que pueda en lugar de intentar evitarlo).

Más sobre Project.json

Tal vez el archivo más significativo de la nueva estructura de proyecto de .NET Core es project.json. Este archivo está diseñado para:

  • Reemplazar el archivo package.config del administrador de archivos NuGet, que identifica las referencias NuGet del proyecto.
  • Especificar los marcos que admite el proyecto y los detalles de configuración sobre cómo se debe compilar el proyecto para el marco concreto.
  • Identificar la plataforma de destino de las aplicaciones autocontenidas, que incluyen todas las dependencias, incluidos los tiempos de ejecución de .NET Core específicos de la plataforma, necesarios para la plataforma correspondiente. O si el proyecto es una aplicación portable, project.json identifica los marcos que el proyecto espera que se instalen en la máquina de destino en la que el ensamblado se ejecutará.

Estas tres tareas se extienden por las cuatro secciones principales dentro de project.json (combino tiempos de ejecución y soportes a medida que se solapa la funcionalidad, en función del tipo de proyecto):

Dependencias: en esta sección se enumeran cada uno de los paquetes NuGet de los que depende el proyecto, incluido el número de versión de dichas dependencias. Los números de versión se pueden especificar con comodines, de forma que se puede permitir "la versión más reciente" que coincida con el comodín para que la restauración del administrador de paquetes NuGet la descargue automáticamente. Una pareja de comillas vacías en el número de versión indica "Usar el último disponible". Además, aunque se pueden agregar referencias mediante la ventana del administrador de paquetes NuGet de Visual Studio, también puede confiar en la forma en que Visual Studio carga de forma asincrónica IntelliSense con los paquetes disponibles del origen de paquetes o la fuente que tenga configurados (consulte la Figura 5). IntelliSense funciona tanto para el nombre del paquete como para el número de versión.

IntelliSense se carga dinámicamente con la lista de paquetes y versiones disponibles
Figura 5. IntelliSense se carga dinámicamente con la lista de paquetes y versiones disponibles

Marcos: en esta sección, identifica los marcos en los que se ejecutará el proyecto; por ejemplo, net45, netstandard1.5 o net40. Además, puede proporcionar buildOptions, dependencias, frameworkAssemblies e imports específicos de la aplicación para el marco identificado. Por ejemplo, para permitir código no seguro para el entorno de ejecución .NET 45, puede especificar dentro del elemento frameworks:

"net45": {"buildOptions": {"allowUnsafe": true}}

Tiempos de ejecución y soportes: si project.json usa tiempos de ejecución o soportes depende de si el proyecto se ha destinado como una aplicación portable o autocontenida. En las aplicaciones autocontenidas, la sección runtimes identifica los sistemas operativos que se admitirán y, por tanto, las bibliotecas de tiempo de ejecución que se incluirán dentro de la aplicación. Una aplicación autocontenida no tiene dependencias (al menos, en lo que incumbe a .NET) de nada instalado previamente en la máquina de destino.

Por contra, la sección supports identifica en las aplicaciones portables las dependencias de tiempo de ejecución que una aplicación buscará cuando se inicie (cualquiera de ellas será suficiente). La lista no es restrictiva (puede ejecutarla en otro lugar), pero un elemento supports provocará que NuGet compruebe que todas las dependencias se hayan satisfecho.

Aunque project.json es crítico dentro de RC1 y RC2, paradójicamente, no mucho después de que se publicase RC2, los equipos de .NET Core y ASP.NET determinaron que project.json era de hecho redundante con el ya asentado archivo de proyecto MSBuild, que ya admite una funcionalidad significativamente mayor, entre la que se incluye la configuración, las dependencias de compilación, los destinos de compilación, las marcas de compilación, la configuración de propiedades de variables de entorno y línea de comandos, y los comandos de compilación. En lugar de reinventarlo todo, el equipo empezó revisando lo que desencadenaba la creación del archivo project.json y se dio cuenta de que los archivos *.*PROJ solían estar muy sobredimensionados: por ejemplo, se enumeraban todos los archivos de un proyecto de forma individual, en lugar de usar patrones globales (comodines). El sobredimensionamiento es tan significativo que, los desarrolladores raramente abren y revisan el archivo antes de ejecutar una compilación, incluso aunque el archivo potencialmente pueda tener algunos comandos no deseables en él. En lugar de crear un archivo de compilación completamente nuevo, el equipo decidió en su lugar corregir el sobredimensionamiento dentro de los archivos *.*PROJ e incluso proporcionar una utilidad de línea de comandos para modificarlos. Lo único que tiene project.json que los archivos *.*PROJ no es la sintaxis JSON (pero, al fin y al cabo, JSON solo es XML contemporáneo, como XML fue [en su día] el archivo plano o el archivo INI contemporáneos). Para más información sobre la potencial desaparición de project.json, consulte el anuncio de Damian Edwards durante el encuentro ASP.NET Community Standup del 10 de mayo de 2016 y la publicación correspondiente de Alexandre Mutel (bit.ly/1NJ9r31), junto con el resumen de Willem Meints en su blog (bit.ly/1sJc2An).

Depuración del código fuente de paquetes

Una de las características que me parece más interesante es la nueva compatibilidad para depurar y depurar paso a paso por instrucciones los paquetes, e incluso modificar el código fuente de los paquetes si está disponible. Suponga, por ejemplo, que tiene un ensamblado "Framework" que abarca toda la compañía y que comparten numerosos equipos. Sin embargo, el paquete Framework es esencialmente código abierto, de forma que cualquiera dentro de la compañía (o incluso mejor, fuera de la compañía) puede contribuir con mejoras y cambios. Ahora, imagine que hace referencia al paquete NuGet para este Framework, pero en algún momento sospecha que podría haber un error que deba corregirse o tal vez una mejora justificada. Normalmente, esto requiere trabajar con el código fuente del componente independientemente del proyecto o la solución. ¿Y si en su lugar pudiera descargar el código fuente y actualizarlo como parte de una experiencia integrada junto al desarrollo principal, incluso depurando paso a paso por instrucciones el código sin depender de un servidor de símbolos ni de archivos PDB? Afortunadamente, este es un escenario clave habilitado en Visual Studio 2015.

Por ejemplo, imagine que quiere depurar el paquete Microsoft.Extensions.Logging, que está disponible en GitHub. Para agregarlo y depurarlo dentro del proyecto, querrá descargar (quizá con los comandos git clone o git submodule) el código fuente. A continuación, para que Visual Studio sepa dónde puede encontrar el código fuente, debe modificar el nodo de proyecto global.json, por ejemplo, agregando "submodules\Logging" a la lista de directorios que supervisa:

{
  "projects": [ "src", "test", "submodules\Logging" ],
  "sdk": {
    "version": "1.0.0-*"
  }
}

Por supuesto, puede facilitar la ruta de acceso completa (por ejemplo, si no clonó el código en un subdirectorio). No obstante, tenga en cuenta que el separador de directorios es o bien dos barras diagonales inversas (\\) o bien una barra diagonal única (por ejemplo, c:/users/mark/documents/visual studio2015/Projects/Microsoft.Extensions.Logging).

Cuando Visual Studio consiga encontrar el código fuente después de que global.json se actualice y se guarde, se agregará automáticamente el proyecto a la solución de forma que después pueda depurar el código fuente.

Un algoritmo bastante primitivo se utiliza para determinar el directorio de código fuente que se cargará:

  1. Si alguna de las ubicaciones de código fuente especificadas en global.json contiene una carpeta con el mismo nombre que el paquete (como Microsoft.Extensions.Logging) y esa carpeta contiene un archivo denominado project.json, el depurador utilizará esa carpeta y los archivos de código fuente que haya dentro de ella.
  2. En cualquier otro caso, se carga el binario compilado de la carpeta de paquetes.

Consulte "Debugging ASP.NET 5 Framework Code Using Visual Studio 2015" (Depuración de código de ASP.NET 5 Framework con Visual Studio 2015) que puede encontrar en bit.ly/22niJ7w para más información.

Resumen

Si aún no ha comenzado a indagar sobre .NET Core, ahora es un momento idóneo para hacerlo, ya que obtendrá el mayor período de tiempo para amortizar la curva de aprendizaje. Para los que contemplan la posibilidad de actualizar desde versiones anteriores, también se cumple. Hay bastantes probabilidades de que actualice en algún momento, y cuanto antes lo haga, antes podrá aprovechar sus nuevas características.


Mark Michaelis es fundador de IntelliTect y trabaja de arquitecto técnico como jefe y formador. Durante casi dos décadas, ha sido MVP de Microsoft y director regional de Microsoft desde 2007. Michaelis trabaja con varios equipos de revisión de diseño de software de Microsoft, como C#, Microsoft Azure, SharePoint y Visual Studio ALM. Hace presentaciones en conferencias de desarrolladores y escribió varios libros, siendo el más reciente “Essential C# 6.0 (5th Edition)” (itl.tc/EssentialCSharp). Póngase en contacto con él en Facebook en facebook.com/Mark.Michaelis, en su blog IntelliTect.com/Mark, en Twitter @markmichaelis o a través de la dirección de correo electrónico mark@IntelliTect.com.

Gracias a los siguientes expertos técnicos de IntelliTect por revisar este artículo: Kevin Bost, Andrew Scott y Michael Stokesbary