.NET Core Framework

Dé el paso hacia la multiplataforma con .NET Framework

Cheryl Simmons

La mayoría de desarrolladores prefiere escribir su código de lógica de negocios una vez y reutilizarla más adelante. Se trata de un enfoque mucho más sencillo que la creación de diferentes aplicaciones cuando se tienen múltiples plataformas de destino. Los anuncios recientes sobre .NET Core (una versión formada por componentes de Microsoft .NET Framework) y la estrecha asociación entre Microsoft y Xamarin implican que si se crean bibliotecas de clases portables (PCL) compatibles con .NET Core, se está más cerca que nunca de conseguir esto.

Sin embargo, ¿qué sucede con las bibliotecas de .NET Framework existentes? ¿Cuánto trabajo conllevará hacer que sean compatibles entre plataformas y convertirlas a PCL? Escriba el analizador de portabilidad de .NET. Con un par de técnicas simples y realizando algunos cambios en el archivo de proyecto, podría ayudar a facilitar el proceso.

La herramienta de analizador de portabilidad de .NET es una extensión de Visual Studio que ha creado el equipo de .NET Framework. Puede usarlo con cualquier versión reciente de Visual Studio que admita extensiones. Simplemente, apunte al analizador de portabilidad en los ensamblados o proyectos, y la herramienta proporciona un resumen, un informe detallado y recomendaciones acerca de las API que se debe usar para mejorar la compatibilidad. Para los proyectos, la herramienta muestra los mensajes de error y le lleva a las líneas de código que se deben cambiar. También ofrece resultados para plataformas clave de Microsoft y se puede configurar para proporcionar resultados a otras plataformas como Mono y Xamarin.

El analizador de portabilidad de .NET tiene un elemento del mismo nivel que la aplicación de consola denominado analizador de portabilidad de API (que puede descargar en aka.ms/w1vcle), que genera resultados similares a los que genera el analizador de portabilidad. En este artículo, me centraré en el uso de la extensión de Visual Studio. También es importante tener en cuenta que puede haber algunas actualizaciones de la extensión del analizador de portabilidad de .NET entre el momento en que se escribe este artículo y su fecha de publicación, por lo que la apariencia de la herramienta puede ser distinta de las imágenes que aparecen aquí.

Prepárese para el éxito

Para que una biblioteca se mueva correctamente entre plataformas, debe estar factorizada de forma adecuada y contener principalmente lógica de negocios. El código de interfaz de usuario debe separarse en otros proyectos. Sin embargo, dado que .NET Core es un subconjunto de .NET Framework, aunque el código esté correctamente factorizado, puede que sus bibliotecas usen API que no se admitan en .NET Core.

En algunos casos, existen API alternativas que consiguen lo mismo. En estos casos, el analizador de portabilidad le sugerirá una API alternativa. En otros casos, no hay ningún sustituto y tendrá que factorizar el código específico de la plataforma. Por último, incluso si desconoce si el ensamblado está correctamente factorizado, puede utilizar el analizador de portabilidad para llevar a cabo una evaluación rápida.

Para usar la extensión, necesitará Visual Studio 2013 o 2014. El siguiente paso es instalar la extensión. Puede encontrarla buscando .NET Portability Analyzer en la Galería de Visual Studio o ir directamente a aka.ms/lah74y.

Haga clic en el botón Descargar y elija Abrir. El siguiente cuadro de diálogo le permite elegir la versión de Visual Studio en la que desea aplicar la extensión. Haga clic en Instalar para iniciar la instalación y, a continuación, haga clic en Cerrar para que el cuadro de diálogo desaparezca. Ya está listo para elegir las plataformas de destino y analizar ensamblados o proyectos.

Elegir las plataformas de destino

El analizador de portabilidad ofrece resultados de forma predeterminada para .NET Framework, ASP.NET vNext (también conocido como .NET Core), Windows y Windows Phone. Puede especificar opciones adicionales si accede a la entrada del analizador de portabilidad de .NET en el menú Herramientas | Opciones de Visual Studio y selecciona el conjunto de plataformas que quiere tener como destino, como se muestra en la Figura 1.

Selección de las plataformas de destino para el proyecto
Figura 1. Selección de las plataformas de destino para el proyecto

Ejecutar el analizador de portabilidad

Hay dos maneras para analizar los ensamblados y proyectos:

  • Para analizar los ensamblados o archivos ejecutables que ya se han generado, acceda al analizador de portabilidad desde el menú Analizar en Visual Studio y vaya a la ubicación del ensamblado. Con esta opción, la herramienta genera un resumen y un informe detallado.
  • Para analizar los proyectos, haga clic con el botón secundario en el proyecto de destino en el Explorador de soluciones. Elija Analizar | Analizar la portabilidad de ensamblado (vea la Figura 2), que es específico para el proyecto seleccionado. Con esta opción, la herramienta genera un resumen, un informe detallado y envía un mensaje a la Lista de errores que proporciona un nombre de archivo y el número de línea donde se produce el problema. También puede hacer doble clic en cada mensaje y la herramienta se desplazará a la línea de código especificada.

Selección del análisis de la portabilidad de ensamblado para un proyecto específico
Figura 2. Selección del análisis de la portabilidad de ensamblado para un proyecto específico

Para probar la herramienta, he abierto un proyecto en el que estuve trabajando hace aproximadamente un año: un juego de palabras que tiene como destino Windows Phone Silverlight 8. Comencé con mi lógica de negocios en una biblioteca de clases portables (PCL) con Windows Phone 8 y Windows 8 como destinos. La idea era reutilizar la biblioteca para implementar la misma aplicación para Windows. Sin embargo, me topé con algunos problemas y tenía prisa, por lo que cambié mi enfoque y mi biblioteca ahora solo tiene Windows Phone Silverlight 8 como destino.

Mi intención es analizar la portabilidad de la biblioteca, realizar los cambios de código necesarios y, a continuación, convertir el proyecto a un proyecto PCL y marcar como destinos Windows 8.1, Windows Phone 8.1 y Windows Phone Silverlight 8.1. También quiero probar la compatibilidad con .NET Core. El analizador de portabilidad me permite echar un vistazo al trabajo que debo realizar sin llegar a convertir el proyecto, cambiando los destinos y tratando de solucionar los errores de compilación. También tengo curiosidad por ver si puedo usar mi biblioteca para compilar una aplicación de Android, por lo que he configurado la herramienta para proporcionar resultados también para Xamarin.Android.

Ejecuto la herramienta y los resultados son prometedores. En la Figura 3 se muestra el resumen, el informe detallado, los mensajes de error y la dirección URL del informe. Según el resumen, puedo ver que mi biblioteca es bastante compatible con todas las plataformas. Es cien por cien compatible con Windows Phone Silverlight 8.1, lo que no me sorprende, teniendo en cuenta que Windows Phone Silverlight 8 era el destino original.

El informe detallado de compatibilidad que muestra las plataformas compatibles
Figura 3. El informe detallado de compatibilidad que muestra las plataformas compatibles

Los resultados detallados son una visualización de tipo hoja de cálculo que muestra solo las API que no son compatibles con una o varias de las plataformas de destino. Los detalles son fáciles de examinar. Están marcados con una X roja que indica donde no se admite una API y una marca de verificación verde para indicar que sí se admite. Es importante tener en cuenta que las API compatibles con todas las plataformas (y que, por tanto, no requieren refactorización) no aparecerán en este informe.

Los detalles incluyen también una columna con cambios recomendados, que señalan API alternativas que funcionarán en varias plataformas. En la parte inferior de los detalles, el informe incluye un vínculo para Volver al resumen. Sirve para volver hacia atrás a la parte superior del resumen. Mis resultados son muy cortos, pero en los informes más largos esta funcionalidad de "volver al principio" es muy útil.

Dado que he analizado un proyecto, mi informe contiene los mensajes de la Lista de errores que indican el archivo y el número de línea donde se produce el uso. Si hago clic en el mensaje, la herramienta me lleva al archivo y la línea indicados en el mensaje.

Si desea obtener acceso a los resultados fuera de Visual Studio, se almacenan en un archivo HTML (ApiPortability­Analysis.htm) que se ubica en el mismo directorio del proyecto del ensamblado de destino. La ubicación se indica en la sección Dirección URL de la parte superior del informe, como se muestra en la Figura 4.

Los resultados del análisis de portabilidad almacenados para su acceso fuera de Visual Studio
Figura 4. Los resultados del análisis de portabilidad almacenados para su acceso fuera de Visual Studio

Trabajo en curso

Se espera que el analizador de portabilidad de .NET, sus resultados y la guía cambian a medida que el equipo de .NET recopile más información (consulte la Figura 5). El equipo recopila datos anónimos sobre el uso de las API cuando se utiliza la herramienta o su equivalente de la aplicación de consola y se resumen en bit.ly/14vciaD.

Este sitio muestra los niveles de uso de las API de .NET
Figura 5. Este sitio muestra los niveles de uso de las API de .NET

El sitio tiene muestra de forma predeterminada las API que requieren más cambios de código. Puede cambiar este comportamiento si modifica el valor en la lista desplegable Show (no se muestra en la imagen). También puede mantener el mouse sobre los iconos "R" o "S" y ver las mismas recomendaciones de código que muestra el analizador de portabilidad. 

Cada nombre de API de la lista es un vínculo que lleva a una página de informes sobre las plataformas en las que se admite la API. El equipo seguirá actualizando el sitio y probablemente se abrirá para que los clientes puedan contribuir, así que visítelo periódicamente.

Convertir la biblioteca en multiplataforma

Ahora es el momento de arreglar mi biblioteca. Sé que quiero que mi biblioteca funcione con Windows Phone 8.1 y Windows 8.1 y veo algunos problemas. Se aplicará un enfoque diferente para cada uno de los problemas.

Usar la abstracción de plataforma Hay dos entradas relacionadas con el flujo de recursos. Según el informe, estas API no se admiten en Windows 8.1 o Windows Phone 8.1. La herramienta no recomienda ninguna API por la que la pueda sustituir, así que necesito quitar este código de mi biblioteca. El informe indica que estos dos miembros se usan en pocas líneas de código idénticas, que cargan un archivo de diccionario estático:

WordList = new ObservableCollection<string>();
StreamResourceInfo info =
  Application.GetResourceStream(new
  Uri("/WordLibWP;component/US.dic", UriKind.Relative));
StreamReader reader = new StreamReader(info.Stream);
string line;
while ((line = reader.ReadLine()) != null)
{
  WordList.Add(line);
}
reader.close();

Sé que puedo usar las API de Windows.Storage en Windows 8.1 y Windows Phone 8.1 para cargar un archivo de recursos, pero entonces mi biblioteca no sería compatible con Windows Phone Silverlight. Para un mayor alcance, he decidido abstraer este fragmento de código específico de plataforma. La abstracción de plataforma es una técnica útil para proporcionar una biblioteca que defina el comportamiento, pero implementando ese comportamiento de forma diferente en el código específico de plataforma. Si desea que el código sea compatible entre plataformas, es una técnica que debe conocer.

Aquí se muestran los pasos básicos que realicé para conseguirlo:

  • Definir el comportamiento en la biblioteca multiplataforma: Para ello, se crea una clase abstracta en la biblioteca que defina un método para leer el archivo de diccionario. También he definido una propiedad que es una instancia de la clase DictionaryReader. De esta forma:
public abstract class DictionaryReader
{
  public abstract Task<ObservableCollection<string>>
    ReadDictionaryAsync(string path);
  public static DictionaryReader Instance { get; set; }
}
  • Implementar el comportamiento en el código específico de plataforma: Para ello, derivo de la clase DictionaryReader en el proyecto de Windows Phone Silverlight. Ofrezco una implementación del método ReadDictionaryAsync que carga y lee el archivo de diccionario como un recurso de aplicación. Observe que este código es básicamente el mismo que el código de mi biblioteca, con algunas comprobaciones de errores en la ruta de acceso de los recursos, ya que necesito un formato específico para que el código de teléfono funcione. Mi implementación para otras plataformas será diferente en función de las técnicas para leer un recurso de aplicación local de esas plataformas. Sin embargo, con la abstracción que he agregado (como se muestra en la Figura 6), esto no debería ser un problema.
  • Inicializar la instancia definida por la biblioteca en la implementación específica de la plataforma: Para ello, agrego código a la clase App de mi proyecto de Windows Phone. Este código inicializa la instancia de DictionaryReader en mi implementación específica de teléfono que lee el archivo como un recurso. De nuevo, este código se encuentra en mi proyecto específico de la plataforma y no en el proyecto que he analizado:
public App()
{
  DictionaryReader.Instance = new DictionaryReaderPhone();
...
}

Figura 6. Implementación de teléfono para cargar y leer diccionarios

class DictionaryReaderPhone : DictionaryReader
{
  public override async Task<ObservableCollection<string>>
  ReadDictionaryAsync(string resourcePath)
{
  ObservableCollection<string> wordList =
    new ObservableCollection<string>();
  StreamResourceInfo info =
    Application.GetResourceStream(new Uri(resourcePath,
    UriKind.Relative));
  if (info == null)
    throw new ArgumentException("Could not load resource: " +
      resourcePath +
      ". For Windows Phone this should be in the
      Format:[project];component/[filename]");
  else
  {
    StreamReader reader = new StreamReader(info.Stream);
    string line;
    while ((line = await reader.ReadLineAsync()) != null)
    {
    wordList.Add(line);
    }
    reader.Close();
    return wordList;
    }
  }
}

Para obtener otro ejemplo que muestra cómo abstraer el código específico de la plataforma, consulte el artículo de MSDN Library, "Abstracción de plataforma con la Biblioteca de clases portable", en aka.ms/q4sq7l.

Usar una API diferente A continuación, evalúo la entrada para obtener el nombre cultura actual. Hago doble clic en el mensaje de error y encuentro este método:

public string CheckLanguage()
{
  return Thread.CurrentThread.CurrentCulture.Name.Split('-')[0];
}

Según el analizador de portabilidad, puedo usar CultureInfo.CurrentCulture. Dado que CurrentCulture es una propiedad estática de CultureInfo y proporciona la misma información que se obtenía desde el subproceso actual, debería funcionar perfectamente. Reemplazo el código que depende de la obtención de la clase Thread por el código siguiente, que utiliza CultureInfo:

public string CheckLanguage()
{
  return System.Globalization.CultureInfo.CurrentCulture.Name.Split('-')[0];
}

Por el momento, ningún problema

Pruebo los cambios y parece que todo va bien. A continuación, vuelvo a ejecutar el analizador de portabilidad. El informe está limpio, solo con unos cuantos cambios de código, y he elegido la compatibilidad con Xamarin.Android además de mis plataformas de destino originales, como se muestra en la Figura 7.

Ejecución de nuevo del informe de análisis después de realizar los cambios de código
Figura 7. Ejecución de nuevo del informe de análisis después de realizar los cambios de código

El paso final para la conversión multiplataforma es transformar el proyecto de biblioteca de un proyecto de biblioteca específico de teléfono a una PCL a la que pueda hacer referencia desde varias aplicaciones. Al principio, pensé que la manera más fácil y rápida de hacerlo sería realizar una conversión "en contexto" mediante una modificación manual del archivo de proyecto.

Después de investigar un poco y probar algunos de los pasos que encontré, llegué a la conclusión de que modificar manualmente el archivo de proyecto no aporta ventajas destacables. Lo consulté con un miembro del equipo de .NET y estaba de acuerdo. Gran parte de la ayuda que encontrará para modificar manualmente un proyecto supone un cierto punto de partida.

Según el historial del proyecto y cualquier otra actualización que haya hecho, puede acabar con un proyecto roto. Es probable que deba crear un nuevo proyecto PCL tras dedicar tiempo intentando convertirlo manualmente. Además, incluso si el proyecto convertido manualmente funciona en un principio, podría dejar de hacerlo si realiza otros cambios más adelante.

En consecuencia, he creado un nuevo proyecto PCL y recomiendo que haga lo mismo. He copiado los archivos de código en el nuevo proyecto. Cuando he copiado el código, tengo algunos errores de compilación debido a instrucciones using que ya no se aplican a la nueva PCL. Tras eliminarlas, mi biblioteca ya estaba lista para funcionar. He cambiado mi aplicación de Windows Phone Silverlight para que haga referencia a mi nueva PCL y la aplicación ya estaba de nuevo funcionando.

Pruébelo

El analizador de portabilidad no solo me ha ayudado a evaluar rápidamente el trabajo que debía hacer para que mi biblioteca fuera multiplataforma, sino que también ha identificado los problemas específicos de plataforma dentro de mi código hasta las llamadas de métodos y el uso de propiedades. También ha ofrecido sugerencias de API cuando había alternativas disponibles.

Por otra parte, le he mostrado las técnicas para factorizar el código específico de la plataforma. Mis nuevos resultados del analizador de portabilidad indican que mi biblioteca se ejecutará en las plataformas de destino adicionales que deseaba, así como en Xamarin.Android. Finalmente, he podido crear una nueva PCL con los nuevos destinos y hacer referencia a esta PCL desde mi aplicación existente. El nuevo analizador de portabilidad de .NET le ayudará a llevar sus bibliotecas a nuevas plataformas.


Cheryl Simmons ha sido programadora en Microsoft durante 10 años y ha escrito sobre las bibliotecas de clases de .NET Base, Windows Forms, Windows Presentation Foundation, Silverlight, Windows Phone y herramientas relacionadas.

Gracias a los siguientes expertos técnicos de Microsoft por revisar este artículo: Matt Galbraith, Daniel Plaisted y Taylor Southwick