.Net Core 3.0: Oficialmente Lanzado

El 23 de septiembre se anuncio el lanzamiento oficial de .Net Core 3.0. Esta versión tiene muchas mejoras muy esperadas por los desarrolladores. Entre ellas se encuentran la posibilidad de crear aplicaciones Windows Forms y Windows Presentation Foundation con .Net Core, una nueva API JSon, nuevos soportes para ARM64 y muchas mejoras de rendimientos. También se encuentra incluida la versión 8 de C# con características muy interesantes que veremos en este post.

Para empezar veamos los cambio en los componentes. Para esta comparación he utilizado la herramienta NDepend la cual nos permite comparar las 2 versiones de .Net Core. En nuestro caso la versión 2.2 y la 3.0. Puedes descargar la herramienta desde aquí.
Una vez instalada la aplicación y ejecutada, seleccionaremos la opción Compare 2 versions of a code base.

Luego seleccionaremos las carpetas a comparar y le presionaremos el boton ok.

A simple vista podemos ver que disponemos de mas cantidad de ensamblados, 156 para la versión 2.2 y 165 para la versión 3.0. Una vez que términos la ejecución de las comparaciones, mediante algunas consultas, podemos obtener los siguientes resultados:

  • 29 espacios de nombres nuevos.
  • 359 tipos nuevos.
  • 3845 miembros nuevos.
  • 1044 métodos nuevos.
  • 166 Campos nuevos.

Con estos números podemos ver que el equipo de .Net Core ha trabajado muy arduamente y el framework ha crecido significativamente en funcionalidades.

Les dejo los links a las consultas realizadas y los reportes que nos entrega la herramienta NDepend. Aquí.

Novedades

Podemos descargar .Net Core 3.0 desde aqui. También se encuentran disponibles la nueva versión de Visual Studio 2019 16.3 y Visual Studio para MAc 8.3 con el soporte necesario para utilizar .Net Core 3.0. Otros lanzamientos relacionado, tambien muy importantes, son ASP.Net Core 3.0 y Entity Framework 3.0.

Plataformas Soportadas

.Net Core 3.0 es compatible con los siguientes sistemas operativos:

  • Alpino: 3.9+
  • Debian: 9+
  • openSUSE: 42.3+
  • Fedora: 26+
  • Ubuntu: 16.04+
  • RHEL: 6+
  • SLES: 12+
  • macOS: 10.13+
  • Cliente de Windows: 7, 8.1, 10 (1607+)
  • Servidor Windows: 2012 R2 SP1 +

Debemos tener en cuenta que Windows Forms y Windows Presentation foundation por el momento solamente funcionan en entornos Windows.

El soporte para Chips es:

  • x64 en Windows, macOS y Linux
  • x86 en Windows
  • ARM32 en Windows y Linux
  • ARM64 en Linux (kernel 4.14+)

Nota: .NET Core 3.0 ARM64 necesita la versión 4.14 del kernel de Linux o superior. 

Puntos más destacados

Las mejoras clave más importantes que  llaman la atención son las siguientes:

  • .NET Core 3.0 ha sido probado durante meses por muchos equipos de Microsoft que pronto implementarán en entornos productivos con grandes cargas de trabajo .
  • El rendimiento se ha mejorado notoriamente en varios sus componentes.
  • C # 8 agrega streams asíncronos, rango e índices, más patrones y tipos de referencia anulables. Nullable nos permite apuntar directamente a fallas en el código que conducen a NullReferenceException . Puede verlo en mi post anterior donde trato estas mejoras. aquí.
  • .NET Standard 2.1 incrementa el conjunto de tipos que podemos usar en el código. Puede usarse tanto con .NET Core como con Xamarin. .
  • Las aplicaciones de escritorio de Windows ahora son compatibles con .NET Core, tanto para Windows Forms como para WPF (y de código abierto). El diseñador de WPF es parte de Visual Studio 2019 16.3. El diseñador de Windows Forms todavía está en versión preliminar y disponible como descarga VSIX. Descargalo desde aqui
  • Las aplicaciones .NET Core ahora tienen ejecutables por defecto. En las versiones anteriores, las aplicaciones debían iniciarse con el comando dotnet myapp.dll , como dotnet myapp.dll. Nuestras aplicaciones ahora pueden iniciarse con un ejecutable específico de la aplicación, como myapp o ./myapp , dependiendo del sistema operativo.
  • Se han agregado API JSON de alto rendimiento para lectura y escritura, modelos de objetos y escenarios de serialización nuevos. Estas API fueron creadas desde cero sobre el genérico Span<T> y utilizan UTF8 en lugar de UTF16 . Estas API minimizan las asignaciones, lo que da como resultado un rendimiento superior y mucho menos carga de trabajo para el recolector de basura. 
  • El recolector de basura utiliza menos memoria de forma predeterminada. Esta mejora es beneficiosa para escenarios en los que varias aplicaciones están alojadas en el mismo servidor. El recolector de basura también se ha actualizado para hacer un mejor uso de gran cantidad de núcleos, en máquinas con más de 64 núcleos.
  • .NET Core ha sido mejorado para la utilización con Docker permitiendo que las aplicaciones .NET funcionen de manera predecible y eficiente en contenedores. El recolector de basura y el grupo de subprocesos se han actualizado para que funcionen mucho mejor cuando se ha configurado un contenedor con memoria limitada o CPU. Las imágenes Docker de .NET Core son más pequeñas, particularmente la imagen que contiene el SDK.
  • Los Raspberry Pi y ARM ahora son compatibles para permitir el desarrollo de IoT, incluso podemos utilizar el depurador remoto de Visual Studio. Podemos implementar aplicaciones que escuchen sensores e impriman mensajes o imágenes en una pantalla, todo utilizando las nuevas API GPIO. ASP.NET se puede usar para exponer datos como una API o como un sitio que permite configurar un dispositivo IoT.
  • .NET Core 3.0 será reemplazada por .NET Core 3.1 , a mediados de noviembre de este año .NET Core 3.1 será una versión compatible a largo plazo (LTS) (compatible durante al menos 3 años). Microsoft recomienda que se adopte antes .NET Core 3.0 y luego adoptar 3.1 para que nos sea más fácil actualizar nuestras aplicaciones.
  • .NET Core 3.0 estará disponible con RHEL 8 en Red Hat Application Streams, después de varios años de colaboración con Red Hat.
  • Visual Studio 2019 16.3 y Visual Studio para Mac 8.3 es es necesarios para el soporte .NET Core 3.0.
  • Los usuarios de Visual Studio Code debemos usar siempre la última versión de la extensión C # para asegurarse de que funcionen los escenarios más recientes.
  • La implementación de Azure App Service de .NET Core 3.0 está actualmente en curso.
  • La implementación de Azure Dev Ops de .NET Core 3.0 se realizará próximamente. Se actualizará cuando esté disponible.

Conclusión

.NET Core 3.0 es una nueva versión que  incluye un amplio conjunto de mejoras que nos tendrán entretenidos un buen tiempo. Es muy recomendable comenzar adaptar nuestras aplicaciones a la nueva versión para mejorar nuestro rendimiento y soporte. No debemos olvidar que dentro de unos meses estará disponible la versión 3.1, así que es una buena opción migrar nuestras app.

En próximos post veremos más en detalle las nuevas características y funcionalidades.


[Article] Asp.Net Core | Trabajando con Cache Distribuido

Vamos a continuar con el tema de uso de cache pero esta vez lo veremos Distribuido. El caché distribuido puede ayudar no solamente en la performance las aplicaciones sino también en la escalabilidad de nuestras aplicaciones.

Objetivo

El objetivo de esta publicación es tocar las posibles utilizaciones y alcance del manejo de del caché distribuido para mejorar la performance y la escalabilidad en nuestras aplicaciones Asp.Net Core.

Audiencia

Este documento está dirigido a desarrolladores que quieren conocer Asp.Net Core y el uso de cache distribuido o personas que desarrollan tareas de Consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

¿Qué es el caché distribuido? Significa que podemos usar caché y múltiples servidores. En el caso de Microsoft Azure puede ser alrededor del mundo. El uso de cache distribuido tiene muchas ventajas como, por ejemplo:

  • Los datos almacenados en el caché siempre son coherentes entre los servidores. No depende de donde el usuario consulte los datos todos verán la misma información.
  • Si es necesario reiniciar un equipo el cache seguirá vivo como también si los servidores necesitan escalar su capacidad. Se pueden agregar o quitar servidores sin necesidad de afectar al cache.
  • Las bases de datos o repositorios de datos tendrán menos consultas, un muchos casos a veces hasta ninguna.

Como cualquier caché existente implementar caché distribuido puede aumentar significativamente la capacidad de respuesta de nuestras aplicaciones debido que los datos son recuperados más rápido que desde una base de datos. También pueden reducir el costo de consumo de nuestros repositorios de bases de datos ya son de menor costo.

Vamos a ver 2 configuraciones una como configurar Redis y el Caché distribuido de sql server. Para esto dependemos de la interface IDistributedCache.

En IDistributedCache tenemos disponible tanto método sincrónicos como asincrónicos. Esta nos permite agregar, recuperar o eliminar elementos que tengamos en el caché. Veamos los métodos:

  • Get, GetAsync Recupera los datos del caché por medio de una key.
  • Set, SetAsync Agrega un tiem al caché por medio de una key.
  • Refresh, RefreshAsync Actualiza el caché por medio de un key reiniciando el tiempo de expiración.
  • Remove, RemoveAsync Elimina un objeto del caché.

Para poder utilizar la interfaz debemos seguir los siguientes pasos:

  1. Implementar en nuestra aplicación paquete nuget.
  2. Configurar en nuestro archivo startup.cs dentro de ConfigureService para que nos lo agregue en nuestro contenedor.
  3. Por último, agregarlo en los constructores de nuestros controller donde lo vamos a utilizar.

Usando Cache Distribuido Redis

¿Qué es Redis? Redis es un cache distribuido en memoria de origen open-source. Podemos usarlo de forma local o en Azure. Azure provee una implementación llamada Azure Redis Cache.

De la misma forma que antes debemos configurar en nuestro archivo Startup.cs una instancia del RedisDistributedCache para poder tenerla disponibles.


/// &lt;summary&gt;
/// Use Redis Cache in Staging
/// &lt;/summary&gt;
/// &lt;param name="services"&gt;&lt;/param&gt;
public void ConfigureStagingServices(IServiceCollection services)
{

services.AddDistributedRedisCache(options =&amp;amp;gt;
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});
}

Usando Cache Distribuido con SQL Server

SqlSeverCache nos permite utilizar cache distribuido con soporte en base de datos de Sql Server. Con la herramienta de sql-cache podremos crear una tabla con estructura necesaria para tener este soporte.

C:\SqlCacheSample\>dotnet sql-cache create “Data Source=(localdb)\v11.0;Initial Catalog=DistCache;Integrated Security=True;” dbo DbSQLCache

Como resultado tendremos esta tabla:

Una vez todo listo debemos agregarlos a nuestros servicios de la siguiente manera:


public void ConfigureProductionServices(IServiceCollection services)
{

services.AddDistributedSqlServerCache(options =&gt;
{
options.ConnectionString = @"Data Source=(localdb)\v11.0;Initial Catalog=DistCache;Integrated Security=True;";
options.SchemaName = "dbo";
options.TableName = "TestCache";
});

}

Conclusión

Asp.Net Core posee un gran soporte para la utilización de cache en distribuido tanto sea Redis, Azure Cache Redis o SqlCache el cual nosotros podemos aprovechar para aumentar el rendimiento y la escalabilidad de nuestras aplicaciones. Para tener en cuenta Redis mi elección siempre ya que posee

[Article] Asp.Net Core | Mejorar el rendimiento de nuestras Apps con Cache

Uno de nuestros clientes nos pidió que analicemos su aplicación para que aumente su rendimiento. Lo primero que pensamos es usar caché. Asp.Net Core, como otras versiones, tiene un muy buen soporte de Caché en memoria. Trataremos ese tema a continuación.

Objetivo

El objetivo de esta publicación es tocar las posibles utilizaciones y alcance del manejo de del caché en memoria como también que es y para qué son útiles.
Audiencia

Este documento está dirigido a desarrolladores que quieren conocer Asp.Net Core o personas que desarrollan tareas de consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

Usar caché puede aumentar significa mente la performance y la escalabilidad de nuestra aplicación reduciendo el costo en la generación de contenido. Una buena recomendación es la utilización de cache en los datos que cambia con poca frecuencia. Por ejemplo, si tenemos datos recuperados de una base de datos que no es modificada nunca o muy pocas veces, podemos guardar en caché estos datos, por un cierto tiempo, sin la necesidad de consultar todo el tiempo la base de datos o su datasource.

Asp.Net Core, como otra versión, tiene diferentes tipos de cache que podemos utilizar. El más común es un caché basado en memoria el cual es el más utilizado. Este caché es almacenado en la memoria del WebServer.

Para usar cache en memoria debemos hacer uso de IMemoryCache primer debemos utilizar el packete nuget “Microsoft.Extensions.Caching.Memory”, luego, esto debemos inyectarlo como servicio. Veamos el siguiente código el siguiente código:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}

public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}

La configuración de nuestro controller deberia ser de la siguiente manera:

public class HomeController : Controller
{
private IMemoryCache _cache;

public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}

Un método muy util es TryGetValue. Este método nos provee la capacidad de verificar si existe un objeto en el caché por medio de una Key. Si existe nos devuelve como salida el existente.


public IActionResult CacheTryGetValueSet()
{
DateTime cacheEntry;

// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;

// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));

// Save data in cache.
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}

return View("Cache", cacheEntry);
}

Unos métodos más simplistas son GetOrCreate(), creo que el nombre lo dice todo y tambien como la gran mayoria de Asp.Net Core tenemos la posibilidad de utilizarlo de un modo asincrónico por medio de GetOrCrareAsyn().

public IActionResult CacheGetOrCreate()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =&amp;gt;
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});

return View("Cache", cacheEntry);
}

public async Task&amp;lt;IActionResult&amp;gt; CacheGetOrCreateAsync()
{
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =&amp;gt;
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});

return View("Cache", cacheEntry);
}

Nuestro cache en memoria puede ser parametrizado por medio de MemoryCacheEntryOptions. podemos configurar:

  • Un tiempo de experiencia. Es el máximo tiempo que va a mantenerse este y permite renovarlo continuamente.
  • Si el cache es consultado se renueva el tiempo de expiración.
  • Se puede establecer para que nunca se remueva o expire.
  • Por medio de PostEvictionDelegate podemos asociar une evento cuando el cache sea removido.

Veamos los ejemplos en código:

public IActionResult CreateCallbackEntry()
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Pin to cache.
.SetPriority(CacheItemPriority.NeverRemove)
// Add eviction callback
.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);

_cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions);

return RedirectToAction("GetCallbackEntry");
}

public IActionResult GetCallbackEntry()
{
return View("Callback", new CallbackViewModel
{
CachedTime = _cache.Get&lt;DateTime?&gt;(CacheKeys.CallbackEntry),
Message = _cache.Get&lt;string&gt;(CacheKeys.CallbackMessage)
});
}

public IActionResult RemoveCallbackEntry()
{
_cache.Remove(CacheKeys.CallbackEntry);
return RedirectToAction("GetCallbackEntry");
}

private static void EvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.CallbackMessage, message);
}

Conclusión

Asp.Net Core posee un excelente soporte la utilización de cache en memoria la cual nosotros podemos aprovechar para aumentar el rendimiento de nuestras aplicaciones. En próximo post hablaremos de la utilización de cache distribuido a nivel global y otras técnicas para aumentar el rendimiento de nuestras aplicaciones web.

[Article] Asp.Net Core | Globalización y Localización

En estos últimos días estuve analizando una aplicación para convertirla a soporte en múltiples lenguajes. Asp.Net Core nos brinda una gran cantidad servicios en su middleware. Entre ellos tenemos disponibles para manejar la globalización y la localización de una manera muy simple.

Objetivo

El objetivo de esta publicación es tocar las posibles utilizaciones y alcance del manejo de globalización y localización como también que son y para qué pueden sernos útiles.

Audiencia

Este document o está dirigido a desarrolladores que quieren conocer Asp.Net Core o personas que desarrollan tareas de consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

Comencemos aclarando algunos conceptos:

  • Globalización (Globalization) es el proceso por el cual se debe diseñar una aplicación para que pueda responder a diferentes culturas. Esta agrega soporte para entrada de información, también su salida o visualizaciones definida para cierto lenguaje o para un área geográfica específica.
  • La localización (Localization) es la adaptación de una aplicación globalizada para una cultura particular cultura.

Para tener disponibles estas caracteristicas deberemos hacer uso de 2 interfaces IStringLocalizar y IStringLocalizar<T>. Estas 2 últimas hacen uso de las clases ResourceManager and ResourceReader que proveerán la información específica que será recuperada de los archivos de recursos.

Algo para destacar es que no es necesario tener los archivos de recursos disponibles. Si invocamos un valor y no existe un archivo de recurso o valor devolverá el nombre del parámetro. Esto puede utilizarse como idioma por default.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace AspNetCoreGloLoc.Controllers
{
[Route("api/[controller]")]
public class StringTextController : Controller
{
private readonly IStringLocalizer&lt;StringTextController&gt; _localizer;

public StringTextController(IStringLocalizer&lt;StringTextController&gt; localizer)
{
_localizer = localizer;
}
[HttpGet]
public string Get()
{
return _localizer["Title"];
}
}
}

Si necesitamos implementar globalización y localización dentro de código con html una buena opción es usar las interfaces IHtmlLocalizar y IHtmlLocalizar<T>. Debemos hacer uso de los siguientes namespaces Microsoft.AspNetCore.Localization y Microsoft.AspNetCore.Mvc.Localization. Usualmente usamos siempre texto simple antes que html específico.


using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;&lt;/pre&gt;
namespace Localization.StarterWeb.Controllers
{
public class BookController : Controller
{
private readonly IHtmlLocalizer&lt;BookController&gt; _localizer;

public BookController(IHtmlLocalizer&lt;BookController&gt; localizer)
{
_localizer = localizer;
}

public IActionResult Hello(string name)
{
ViewData["Message"] = _localizer["&lt;b&gt;Hello&lt;/b&gt;&lt;i&gt; {0}&lt;/i&gt;", name];

return View();
}
Una opción interesante es la posibilidad de particionar la localización por controlador, área o algún tipo de contenedor. Veamos cómo podemos usar ShareResource para esto.
namespace Localization.StarterWeb
{
public class SharedResource
{
}
}

Podemos usar Startup del proyecto y agregarlo al contenedor global veamos el siguiente controlador de ejemplo:

&lt;/pre&gt;
public class InfoController : Controller
{
private readonly IStringLocalizer&lt;InfoController&gt; _localizer;
private readonly IStringLocalizer&lt;SharedResource&gt; _sharedLocalizer;

public InfoController(IStringLocalizer&lt;InfoController&gt; localizer,
IStringLocalizer&lt;SharedResource&gt; sharedLocalizer)
{
_localizer = localizer;
_sharedLocalizer = sharedLocalizer;
}

public string TestLoc()
{
string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
" Info resx " + _localizer["Hello!"];
return msg;
}

Para una vista podemos usar IViewLocalizer. ViewLocalizer implementa la interface anterior y busca en los archivos de recursos dependiendo el path de la vista.

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
ViewData["Title"] = Localizer["About"];
}
&lt;h2&gt;@ViewData["Title"].&lt;/h2&gt;
&lt;h3&gt;@ViewData["Message"]&lt;/h3&gt;

&lt;p&gt;@Localizer["Use this area to provide additional information."]&lt;/p&gt;
&lt;pre&gt;

Importane!:

  • Es necesario usar el paquete nuget “Localization.AspNetCore.TagHelpers”.
  • Generalmente usamos una sola localizacion para texto y no HTML.

Otra opción que utilizamos mucho puede ser por medio de DataAnnotations.

public class RegisterViewModel
{
[Required(ErrorMessage = "The Email field is required.")]
[EmailAddress(ErrorMessage = "The Email field is not a valid e-mail address.")]
[Display(Name = "Email")]
public string Email { get; set; }

[Required(ErrorMessage = "The Password field is required.")]
[StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }

[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}

Conclusión

Asp.Net Core posee un de características las cuales nosotros como desarrolladores podemos sacarle un muy buen provecho a la localización y globalización. En próximo post hablaremos de la utilización de archivos de recursos para lograr el mismo objetivo.

[Article] Asp.Net Core | Múltiples entornos de trabajo

Una de las nuevas características de Asp.Net Core es la capacidad de trabajar con múltiples entornos de trabajo. Podemos utilizar un entorno de desarrollo, prueba y producción. Esta configuración nos permitirá modificar el comportamiento según el entorno en el cual está ejecutando la aplicación.

Objetivo

El objetivo de esta publicación es tratar los posibles usos de esta nueva característica junto a las buenas prácticas en el desarrollo de aplicaciones.

Audiencia

Este documento está dirigido a desarrolladores que quieren conocer Asp.Net Core o personas que desarrollan tareas de Consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

Supongamos que tenemos 3 entornos donde debemos ejecutar o cargar diferentes configuraciones: Development, Staging y Production. Asp.Net Core nos permite distinguir estos entornos por medio de variables denominadas “Enviroment Variable”. la variable a la cual nos referimos se llama ASPNETCORE_ENVIROMENT.  Esta es la que nos permitirá configurar nuestro entorno de trabajo. Los valores más comunes son Development, Staging y Production.

Una vez configurada esta variable podemos detectar en tiempo de ejecución cuál es el valor de esta variable y en qué entorno nos encontramos corriendo la aplicación.

Debemos tener en cuenta que en Linux el nombre es case sensitive, por esta razón, los archivos y las configuraciones serán tomadas como case sensitive como buena práctica.

Development

Este entorno es que usaremos mientras estamos desarrollando nuestra aplicación. ¿Cómo hacemos para configurarlo? debemos hacer botón derecho sobre nuestro proyecto, seleccionar configuración, se abrirá una ventana y seleccionamos de la solapa izquierda “Debug” como podemos ver en la siguiente ventana.

Recordemos que cuando modifico esta pantalla la configuración es modificada en el archivo launchSessting.json dentro de la carpeta properties . En este archivo podemos incluir cualquier entorno que deseemos, por ejemplo, podemos agregar varios perfiles de configuración como podemos ver en el código siguiente:


{

"iisSettings": {

"windowsAuthentication": false,

"anonymousAuthentication": true,

"iisExpress": {

"applicationUrl": "http://localhost:40088/",

"sslPort": 0

}

},

"profiles": {

"IIS Express": {

"commandName": "IISExpress",

"launchBrowser": true,

"environmentVariables": {

"ASPNETCORE_ENVIRONMENT": "Development"

}

},

"IIS Express (Staging)": {

"commandName": "IISExpress",

"launchBrowser": true,

"environmentVariables": {

"ASPNETCORE_ENVIRONMENT": "Staging"

}

}

}

}

Si cambiamos alguna de estas configuraciones en el archivo no se tomarán los efectos automáticamente. Deberemos reiniciar los servidores, sobre todo Kestrel necesitará reiniciar, una vez que se haya modificado para poder detectar correctamente el cambio.

Staging

Este es el entorno que utilizaremos para un entorno de test o preproducción. Casi siempre para un testing final antes de hacer un pasaje a producción. Casi siempre este entorno debería ser un espejo de producción para reducir el impacto de implementación.

Production

Este es el entorno al que muchas veces denominados Vivo. Es un entorno donde configuramos características de seguridad, rendimiento y la fiabilidad de la aplicación. algunas de las características que puede tener el entorno de producción es:

  • Activar funciones de cache
  • Ajustes de archivos del lado del cliente como paquetes, reduccion de archivos js y css o configuraciones de CDN (Content Delivery Network)
  • Desactivar funciones de diagnóstico
  • Activar configuraciones de registro y monitoreo.

La lista puede ser más extensa dependiendo de las necesidades de cada aplicación.

Configurando los entornos

En Windows podemos hacer uso de la configuración por medio de una vez que se está ejecutando nuestra aplicación:

línea de comandos

set ASPNETCORE_ENVIRONMENT=”Development”

PowerShell

$Env:ASPNETCORE_ENVIRONMENT = “Development”

Estos comandos solamente serán validados mientras la ventana donde se está ejecutando este abierta. Si la cerramos perderemos esta configuración. En caso de querer que el valor sea global deberemos configurarlo desde Panel de Control > Sistema > Configuración Avanzada de Sistema, en la solapa Opciones Avanzadas deberemos agregar la variable ASPNETCORE_ENVIRONMENT como vemos en la captura siguiente:

En macOS debemos usar desde el bash el siguiente comando

ASPNETCORE_ENVIRONMENT=Development dotnet run

Ha nivel sistema operativo o maquina debemos configurar las variables en los archivos .bashrc o .bash.profile. debemos editar el archivo y agregar los siguiente:

export ASPNETCORE_ENVIRONMENT=Development

En Linux debemos usar el comando export  desde la consola para la sesión abierta o modificar el archivo bash_profile para todo el sistema operativo o máquina .

Cómo verificar en tiempo de ejecución el entorno

Asp.Net provee un servicio basado en la interface IHostingEnviroment que es disponible por medio de Inyección de Dependencia en el contenedor principal. En el archivo startup.cs podemos ver como es inyectada la variable env  la cual nos permitirá acceder al entorno.


public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

if (env.IsDevelopment())

{

app.UseDeveloperExceptionPage();

app.UseDatabaseErrorPage();

app.UseBrowserLink();

}

else

{

app.UseExceptionHandler("/Home/Error");

}

Para chequear un entorno específico mientras estamos ejecutando la aplicación, IHostingEnvironment provee el método IsEnviroment( “Nombre del entorno”).

En el código podemos ver que se está preguntando si el entorno es Development por medio del método IsDevelopment() cual cual configurara algunas opciones para este entorno. Por ejemplo, vemos que se configura app.UseBrowserLink(); que es característica propia de visual studio que en producción no usaremos.

También tenemos la posibilidad de usar estas configuraciones por medio de Tag Helper dentro de las Vistas de MVC. Por ejemplo, podemos decirle que utilice archivos css o js no comprimidos en Develoment y que en Staging y Production los use comprimidos.


&lt;environment names="Development"&gt;
&lt;link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /&gt;
&lt;link rel="stylesheet" href="~/css/site.css" /&gt;
&lt;/environment&gt;
&lt;environment names="Staging,Production"&gt;
&lt;link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /&gt;
&lt;link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /&gt;
&lt;/environment&gt;

Conclusión

Asp.Net Core posee un de características las cuales nosotros como desarrolladores podemos sacarle un muy buen provecho como también un gran control sobre los entornos en los cuales trabajamos habitualmente. Esta configuración nos permite cambiar el comportamiento de nuestra aplicación con un simple cambio de valor en la variable de entorno.

[Article] Asp.Net Core | Manejo errores

Algo muy importante que deberíamos tener en cuenta en el desarrollo de nuestras aplicaciones es un correcto manejo de excepción. En varios de nuestros clientes notamos que no hacen uso de una forma correcta o directamente no es tenido en cuenta. Al ocurrir algún error dentro de una aplicación Asp.Net nos permite manejalo de varias formas de una manera simple y rápida.

Objetivo

El objetivo de esta publicación es tocar las posibles utilizaciones y alcance del manejo de errores propuesto por Asp.Net Core.

Audiencia

Este documento está dirigido a desarrolloradores que deseen conocer Asp.Net core o personas que desarrollan tareas de consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.

Desarrollo

Comencemos enumerando las diferentes tipos de excepciones, configuraciones y opciones que podemos utilizar:

  • Página de excepción para desarrollo.
  • Configurar excepciones personalizadas.
  • Configurando código de estado para las páginas.
  • Manejando código de excepciones.
  • Manejando código de excepciones en el servidor.
  • Manejo de excepción en el inicio de aplicación.
  • Manejo de excepciones en Asp.Net MVC.

Página de excepciones para desarrollo

La configuración por defaults de la página de errores tal vez es poca. Por este motivos, para obtener una mayor cantidad de información podemos instalar el paquete Nuget Microsoft.AspNetCore.Diagnostics. Luego de instalar el paquete debemos hacer la inyección correspondiente en el método Configure que se encuentra en el archivo startup.cs de la siguiente manera.


public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory){
loggerFactory.AddConsole();
env.EnvironmentName = EnvironmentName.Production;

if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}else{
app.UseExceptionHandler("/error");
}
}

  • Recordemos que esto solo debe estar activo cuando la aplicación esté corriendo en un entorno de desarrollo.

Para ver la página  de excepción debemos correr la aplicación seteado en entorno de desarrollo y debemos agregar ?throw=true en la url. Podemos que la página incluye algunos tabs muy interesantes que contienen la información de la excepción y el request que hicimos. La primera solapa es Stack:

La solapa Query muestra los parámetros pasados por Query String si los hay.

La siguiente solapa es Cookies. Si hay cookies en el request van a aparecer en esta solapa.

Por último, tenemos la solapa de Headers donde podemos ver todos los encabezados enviados en el Request.

Configurar excepciones personalizadas

Cuando no estamos trabajando en un entorno de desarrollo es conveniente configurar un manejador especial.


public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory){
loggerFactory.AddConsole();
env.EnvironmentName = EnvironmentName.Production;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
}

En Asp.Net MVC no tenemos un decorador de errores para que ejecute una acción dependiendo de un método http. Para solucionar esto debemos tener un Action que sea ruteado a el como podemos ver en el siguiente código:

[Route("/Error")]
public IActionResult Index()
{
// Handle error here
}

Configurando código de estado para las páginas

Nuestra aplicación, por default, no muestra ningun codigo de estado para un código de estado de HTTP como podría ser el error 500(Internal Server Error) o el 404 (Not Found). Podemos configurar StatusCodePagesMiddleware en el método Configure en el archivo startup.cs

app.UseStatusCodePages();

Este middleware agregara un texto simple como podemos ver en la captura

app.UseStatusCodePages() puede soportar varios tipos de métodos. Alguno pueden ser expresiones del tipo lambda o tipos de contenido o formato de textos como podemos ver en los siguientes codigos:


app.UseStatusCodePages(async context =&gt;
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});

app.UseStatusCodePages("text/plain", "Status code page, status code: {0}");

En otros casos podemos redireccionar directamente a algún método que deseamos. por ejemplo, podemos devolver el error 302 al cliente pero también podemos redireccionarlo a un dirección url.

app.UseStatusCodePagesWithRedirects("/error/{0}");
app.UseStatusCodePagesWithReExecute("/error/{0}");

Si necesitamos desactivarlo por algún motivo simplemente debemos usar el siguiente código:

var statusCodePagesFeature = context.Features.Get&lt;IStatusCodePagesFeature&gt;();

if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}

Manejando código de excepciones.

A menudo es una buena idea para las páginas de error en producción para constan de contenido puramente estática. Hay que tener en cuenta que una vez enviado los encabezados en el response es posible cambiar el estado de la respuesta como tampoco ejecutar otra página de excepción. El response debe ser completado o la conexión abortada.

Manejando código de excepciones en el servidor.

Recordemos que además de manejar las excepciones, en el servidor donde se encuentra alojada la aplicación, realizara alguna gestión sobre esa excepción. Algunos puntos para tener en cuenta son: Si el servidor detecta un error 500 antes de que se envíe al cliente se enviará un error sin contenido. Si se detecta una excepción después de que los cabeceros se han enviado, se cerrara la conexión, por último, las solicitudes que no son manejadas por la aplicación serán manejadas por los servidores. Cualquier configuración que hagamos en el manejo de excepciones no modificarán el comportamiento del servidor.

Manejo de excepción en el inicio de aplicación

Todas las configuraciones y situaciones anteriores ocurren durante el ciclo de vida de la aplicación. En caso de ocurrir un error durante el inicio de la aplicación se disparará una excepción a nivel servidor.

Manejo de excepciones en Asp.Net MVC.

Asp.Ne MVC  tiene algunas opciones mas para poder capturar errores como configurar excepción en los llamados filtros (filter) y validaciones en los modelos.

Exception Filters

Un filtro puede ser configurado de forma global o sobre un controller o  action basado en MVC. Los filtros pueden capturar una excepción que no haya sido configurada con anterior mientras ocurre la ejecución de un controlado o acción. Inclusive en un filtro.

Handling Model  State Errors

El Model Validation se ejecuta cuando el controlador y el action son invocados. Es posible invocarlo con el método ModelState.IsValid para verificar si el modelo está correct.

Conclusión

un buen manejo de errores puede evitarnos un dolor de cabeza muy grande cuando nuestra aplicación está fallando y no sabemos cuál es la causa.