Archivo de la categoría: Programación

Temas relacionados con la programación en general. Lenguajes .Net, java, python, C#, Visual Basic, C…

Localización .Net Core 6 con recursos en ensamblado

Este post es para intentar explicar como utilizar recursos de localización que se encuentran en un ensamblado distinto.

Funciona para .Net Core 6.

Los ficheros de recurso serán de 2 tipos, uno con el modificador de acceso público y otro sin generación de código.

El principal podrá ser el que tiene el modificador «Public»:

El secundario podrá ser el que tiene el modificador «Sin generación de código»:

Todo lo anterior es en lo referente a nuestro ensamblado de recursos (dll).

En el proyecto principal, además de agregar la referencia a nuestro ensamblado deberemos ir a la parte donde se configura los servicios de .net core, en este caso «Program.cs»

Después del sitio donde se añade el servicio de ControllerWithViews

builder.Services
.AddControllersWithViews()
.AddRazorRuntimeCompilation();
//Localization
var supportedCultures = new List
{
new CultureInfo("en"),
new CultureInfo("es")
};
builder.Services.AddLocalization();
builder.Services.Configure(
opts =>
{
opts.DefaultRequestCulture = new RequestCulture(supportedCultures[0]);
opts.SupportedCultures = supportedCultures;
opts.SupportedUICultures = supportedCultures;
opts.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
{
return new ProviderCultureResult(supportedCultures[0].Name);
}));
});

Y después de hacer el build implementar el middleware:

var app = builder.Build();
var options = app.Services.GetService>();
app.UseRequestLocalization(options.Value);

Por último quedaría usarlo, por ejemplo en el controller:

public IActionResult Index()
{
var texto_traducido = Res.HomeAppDescription;
return View();
}

O en la vista:

@inject IStringLocalizer Localizer
<p>Mi traducción es: @Res.HomeAppDescription</p>

Asegurar release siempre en la publicación .Net

La publicación de una aplicación .Net permite utilizar la configuración Debug y Release y dependerá casi siempre de lo que tengamos seleccionado en el momento de la publicación.

Sin embargo, en muchas ocasiones solo nos interesará publicar con la configuración Release.
Sobre todo cuando tengamos en nuestro código sentencias condicionales del tipo:

#if DEBUG

#else

#endif

Para asegurarnos de que siempre utilizaremos la configuración release deberíamos editar el archivo csproj de nuestro proyecto e introducir lo siguiente justo antes del cierre de la etiqueta :

&amp;amp;amp;lt;Target Name=&amp;amp;amp;quot;BeforePublish&amp;amp;amp;quot;&amp;amp;amp;gt;
	&amp;amp;amp;lt;Error Condition=&amp;amp;amp;quot;'$(Configuration)' == 'Debug'&amp;amp;amp;quot; Text=&amp;amp;amp;quot;¡Estás intentando publicar la configuración Debug!&amp;amp;amp;quot; /&amp;amp;amp;gt;
  &amp;amp;amp;lt;/Target&amp;amp;amp;gt;

Problema con scroll en ventana modal bootstrap

En bootstrap al abrir una ventana modal automáticamente se desactiva el scroll de la parte que se encuentra en el background.

Si al cerrar la ventana modal no consigue restablecerse el scroll se puede utilizar el siguiente cambio en el css:

Esto es el css que hace desaparecer el scroll

.modal-open {
    overflow: hidden;
}

Se puede modificar por lo siguiente

.modal-open {
    overflow: scroll;
}

De esta manera el scroll siempre estará activo.

 

Utilizar AsyncPostBackTrigger o Update

Cuando utilizamos un UpdatePanel en Asp.Net WebForms a veces no tenemos en cuenta el uso final al que va destinado. Es decir, en ocasiones se hacen llamadas al servidor que no requieren un refresco del UpdatePanel con lo que no tiene sentido actualizarlo.

Entendiendo el UpdatePanel

Existe una propiedad fundamental para configurar el UdpatePanel y este es el UpdateMode. Puede tener 2 valores: Allways y Conditional.

Si establecemos este valor en Allways, todas las llamadas al servidor de los controles que produzcan un postback harán refrescar el panel. Esta es una opción muy rápida, que además viene por defecto, pero en mi opinión no nos ayuda nada a la hora de aprovechar al máximo los beneficios de AJAX y el UpdatePanel.

Estableciendo el valor UpdateMode en Conditional, deberemos preocuparnos nosotros de indicar qué controles realizarán el update en el panel o bien indicarle en nuestro código cuándo debe actualizarse.

Establecer los controles en la sección Triggers para indicar cuales de ellos producirán un update del panel puede parecer una buena opción, desde luego no está mal, pero ¿por qué deberíamos hacerlo si podemos indicarlo en el código mediante el método Update() del UpdatePanel?

La ventaja de utilizar el método Update() frente por ejemplo AsyncPostBackTriggers es que tenemos controlado en todo momento cuando se debe actualizar el UpdatePanel. Si, por ejemplo, tenemos un método en el servidor que responde a un click de un botón y dentro de este método tenemos condicionales que harán que el resultado sea o no visible para el usuario podremos indicar nosotros mismos cuando una acción alterará los datos visibles en pantalla mediante el método Update().

 

Realizar tareas programadas en una aplicación ASP.Net

Desarrollo y programación .net

Por circunstancias de la vida me he encontrado últimamente con varios proyectos realizados en ASP.Net que requieren realizar tareas programadas que se ejecuten en un momento concreto del día independientemente si existe o no usuarios conectados.

Como suele ocurrir existen muchas maneras de abordar esta funcionalidad:

  • Mediante Servicios Windows, siempre que tengamos total control de nuestro servidor y el entorno para realizar la tarea en cuestión (Base de Datos, acceso al sistema de ficheros, etc.)
  • Mediante WCF. También sería necesario acceso total a IIS y a su configuración.
  • Mediante programación dentro de la misma aplicación ASP.Net.

Seguro que existe alguna otra pero mi objetivo primordial en todos estos proyectos que debía realizar era optimizar los tiempos mantenimiento, para ello creo que la última solución resultaba la mejor en este caso ya que solo tendría que dedicarme a modificar un único proyecto: la aplicación ASP.Net. De otro modo tendría que instalar el servicio windows o configurar el proyecto WCF dentro del IIS.

Así que me puse a investigar por la web cuales eran las mejores prácticas de cómo realizar una tarea programada en background dentro de ASP.Net. Encontré una solución que me parecía muy clara y que muchos reportaban como buena. Su funcionamiento requería del uso de la caché de la aplicación web y el método application_start dentro del global.asax.

Su uso consistía en añadir un objeto a la cache en el contexto de ejecución para que cuando dicha cache expirara utilizara el evento para ejecutar de nuevo la tarea. La palabra clave para este método es CacheItemRemovedCallback… pero os anticipo que yo NO LO UTILIZARÉ MÁS.

No voy a adentrar en los motivos de rehusar finalmente este método pero os puedo asegurar que da problemas, incluso cuando establecemos el tiempo de inactividad a 0 dentro del pool de aplicaciones del IIS, que en principio parecía que podía ser una de las soluciones.

Investigando un poco más pude dar con un componente muy interesante: Quartz.

Su uso es muy sencillo y parece ser que existe un componente homónimo en Java.

Quartz tiene una Interfaz denominada IJob que únicamente expone un método llamado Execute(). Si deseas hacer una tarea a nivel de aplicación únicamente debes llamar JobScheduler.Start() dentro de Application_Start() del Global.asax.

using Quartz;
using Quartz.Impl;
using System;
 
namespace ScheduledTaskExample.ScheduledTasks
{
    public class JobScheduler
    {
        public static void Start()
        {
            IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
            scheduler.Start();
 
            IJobDetail job = JobBuilder.Create&amp;lt;MyJob&amp;gt;().Build();
 
            ITrigger trigger = TriggerBuilder.Create()
                .WithDailyTimeIntervalSchedule
                  (s =&amp;gt;
                     s.WithIntervalInHours(24)
                    .OnEveryDay()
                    .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(0, 0))
                  )
                .Build();
 
            scheduler.ScheduleJob(job, trigger);
        }
    }
}

Timeout en MySQL con Entity Framework

Si se produce un timeout en MySQL con Entity Framework la primera opción que se nos podría ocurrir es agregar el parámetro default command timeout en la cadena de conexión:

<add name="Entities" connectionString="metadata=res://*/DAL.MyModel.csdl|res://*/DAL.MyModel.ssdl|res://*/DAL.MyModel.msl;provider=MySql.Data.MySqlClient;provider connection string='server=localhost;persistsecurityinfo=False;user id=root;password=;database=myddatabase;default command timeout=300'" providerName="System.Data.EntityClient" />

Por desgracia esta solución no funciona debido a un bug en el connector / NET de MySQL. Ver ref. bug.

Por suerte existe una opción para cambiar este valor para el object context en Entity Framework, dependiendo de la versión de Entity Framework:

Entity Framework 6:

this.context.Database.CommandTimeout = 180;

Entity Framework 5:

((IObjectContextAdapter)this.context).ObjectContext.CommandTimeout = 180;

Entity Framework 4 e inferiores:

this.context.CommandTimeout = 180;

Convertir UNIX TimeStamp a DateTime

Es posible que en alguna ocasión en tu vida de programador te hayas encontrado con valores de fecha que aparentemente no lo son, pueden ser generalmente valores enteros muy grandes como por ejemplo 1415463675.

En mi experiencia lo que puedes estar viendo es un valor almacenado en un formato Excel o un UNIX timestamp.

Para convertir UNIX TimeStamp a DateTime en C# .Net podremos utilizar lo siguiente:

public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
    // Unix timestamp son los segundos pasados después de una fecha establecida, por lo general unix utiliza esta fecha 
    System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
    dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
    return dtDateTime;
}

De esta manara podrás ver que el valor 1415463675 se corresponde a la fecha 11/08/2014 / 4:21pm (UTC).

Copiar y restaurar bases de datos MySQL con codificación de caracteres intacta

Si quieres preservar caracteres como ñ, ó, ç u otros del estilo cuando migras una base de datos MySQL deberás usar mysqldump con las siguientes opciones:

mysqldump -u <tu_usario> -p <tu_password> –default-character-set latin1 –skip- character-set <tu_db> archivo.sql

Para restaurarla:

mysql -u <tu_usuario> -p <tu_password> –default-character-set latin1 <tu_db> < archivo.sql 

Esto solucionará problemas al restaurar copias de seguridad mediante código. En mi código .Net realizaba un proceso que creaba tanto la copia de seguridad en scripts .sql y también tenía otro proceso que realizaba la copia de seguridad a partir del fichero generado anteriormente. Sin embargo si el comando lo ejecutaba a través de la consola de windows el proceso lo realizaba correctamente.

Aparentemente el primer proceso generaba correctamente el archivo sql pero a la hora de ejecutar el proceso no podía continuar cuando encontraba un caracter especial, (en mi caso la ñ).

Si realizas copias programadas también deberás tenerlo en cuenta sobre todo si ejecutas la restauración mediante alguna aplicación .net. Y sobre todo leer el fichero de esta manera:

StreamReader reader = new StreamReader(file,Encoding.GetEncoding(«latin1»));

Como ves los ingleses lo tienen más fácil porque nunca le ocurrirán problemas de este tipo a no ser que trabajen con aplicaciones multiidioma. Pero en cualquier caso deberías tener siempre en cuenta copiar y restaurar bases de datos MySQL con codificación adecuada.