Archivo de la etiqueta: c#

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<MyJob>().Build();
 
            ITrigger trigger = TriggerBuilder.Create()
                .WithDailyTimeIntervalSchedule
                  (s =>
                     s.WithIntervalInHours(24)
                    .OnEveryDay()
                    .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(0, 0))
                  )
                .Build();
 
            scheduler.ScheduleJob(job, trigger);
        }
    }
}
Realizar tareas programadas en una aplicación ASP.Net
4 (80%) 1 vote

10 consejos para programadores C#.Net

En esta entrada daremos 10 consejos para programadores C#.Net que puedan ser de utilidad y que en muchos casos no son muy conocidos.

Desarrollo y programación .net
Programador .Net
Consejo 1: Escribir pruebas unitarias para métodos no públicos

Seguro que si trabajas con proyectos que requieren un control de calidad has tenido que introducir algún proyecto de tests que impliquen pruebas unitarias. En ese caso seguro que has tenido problemas al intentar probar algún método que no es público. C# permite hacer visibles los ensamblados internos a otros ensamblados. Para solucionarlo añadiremos el siguiente atributo en el AseemblyInfo.cs.

//Hacer visible a un determinado ensamblado
[assembly: InternalsVisibleTo("MyTestAssembly")]
Consejo 2: Usar tuplas

En ocasiones es mejor utilizar una tupla contenedora de valores tipados que utilizar clases POCO, sobre todo cuando la estructura de datos creada solo se va a utilizar en un momento puntual.

public Tuple<int, string, string> GetEmployee()
{
	int employeeId = 1001;
	string firstName = "Rudy";
	string lastName = "Koertson";

	//Crear una tupla y devolverla
	return Tuple.Create(employeeId, firstName, lastName);
}
Consejo 3: No hay necesidad de crear colecciones temporales, mejor usar yield

Habitualmente creamos estructuras temporales de tipo enumerables para devolverlas en un método. Algo parecido a lo siguiente:

public List<int> GetValuesGreaterThan100(List<int> masterCollection)
{
	List<int> tempResult = new List<int>();

	foreach (var value in masterCollection)
	{
		if (value > 100)
			tempResult.Add(value);
	}
	return tempResult;
}

En estos casos podemos ahorrar un par de líneas de código utilizando el comando yield. A continuación mostramos el ejemplo anterior pero usando yield:

public IEnumerable<int> GetValuesGreaterThan100(List<int> masterCollection)
{
	foreach (var value in masterCollection)
	{
		if (value > 100)
			yield return value;
	}
}
Consejo 4: Comunicar que el método está obsoleto

Si tu librería está siendo usada por diferentes clientes y deseas que algún método deje de ser utilizado porque existe otro método que los sustituye o simplemente porque ya no funciona puedes indicarlo con el siguiente atributo:

[Obsolete("Este método estará obsoleto pronto. Para reemplazarlo se puede utilizar el método XYZ.")]
public void MyComponentLegacyMethod()
{
	//Aquí la implementación
}

El código anterior provocaría una advertencia o warning en el código que invocara este método. Sin embargo si deseas que ya no se pueda utilizar de ninguna de las maneras utilizarías un parámetro adicional boleano como True.

[Obsolete("Este método estará obsoleto pronto. Para reemplazarlo se puede utilizar el método XYZ.", true)]
public void MyComponentLegacyMethod()
{
	//Aquí la implementación
}
Consejo 5: Recuerda que las consultas de linq son diferidas

Cuando se realiza una consulta en linq solo se ejecuta realmente cuando se accede a los resultados. Esto se llama ejecución diferida. Para que solo se ejecute una vez la consulta debemos utilizar el método ToList.

public void MyComponentLegacyMethod(List<int> masterCollection)
{
	//Sin el método ToList esta consulta de linq sería ejecutada dos veces
	var result = masterCollection.Where(i => i > 100).ToList();

	Console.WriteLine(result.Count());
	Console.WriteLine(result.Average());
}
Consejo 6: Convertir entidades de negocio usando la palabra clave Explicit

Usar Explicit para definir la conversión de entidades. El método de conversión será invocado cuando se necesite. Un ejemplo:

class Program
{
	static void Main(string[] args)
	{
		ExternalEntity entity = new ExternalEntity()
		{
			Id = 1001,
			FirstName = "Dave",
			LastName = "Johnson"
		};
		MyEntity convertedEntity = (MyEntity)entity;
	}
}

class MyEntity
{
	public int Id { get; set; }
	public string FullName { get; set; }

	public static explicit operator MyEntity(ExternalEntity externalEntity)
	{
		return new MyEntity()
		{
			Id = externalEntity.Id,
			FullName = externalEntity.FirstName + " " + externalEntity.LastName
		};
	}
}

class ExternalEntity
{
	public int Id { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
}
Consejo 7: Mantener el Stack Trace original

En .Net cuando se usa un bloque catch para capturar una excepción y se vuelve a lanzar se pierde información ya que se entiende que se ha controlado y que la excepción se genera desde el bloque que la capturó. Ejemplo:

public void RunDataOperation()
{
	try
	{
		Intialize();
		ConnectDatabase();
		Execute();
	}
	catch (Exception exception)
	{
		throw exception;
	}
}

Para mantener la traza original del error haremos esto:

public void RunDataOperation()
{
	try
	{
		Intialize();
		ConnectDatabase();
		Execute();
	}
	catch (Exception)
	{
		throw;
	}
}
Consejo 8: Atributo Flags – Agrupamiento de enum

Mediante el atributo Flags dentro de una enumeración permitirá agrupar los valores de enum. A continuación un ejemplo en el que la salida será: “BlackMamba, CottonMouth, Wiper“.

class Program
{
	static void Main(string[] args)
	{
		int snakes = 14;
		Console.WriteLine((Reptile)snakes);
	}
}

[Flags]
enum Reptile
{
	BlackMamba = 2,
	CottonMouth = 4,
	Wiper = 8,
	Crocodile = 16,
	Aligator = 32
}
Consejo 9: Forzar el tipo base para un tipo genérico

Partamos de que hemos creado una clase genérica donde hay que cumplir que el tipo genérico previsto en la clase debe heredar de una interfaz específica, esto se puede hacer como se muestra en el ejemplo siguiente:

class MyGenricClass<T> where T : IMyInterface
{
	//Cuerpo de la clase iría aquí
}

O incluso a nivel de método:

class MyGenricClass
{
	public void MyGenericMethod<T>(T t) where T : IMyInterface
	{
		//Implementación genérica iría aquí
	}
}
Consejo 10: Exponer una propiedad como IEnumerable no significa que sea solo lectura

Imaginemos que creamos una clase con una propiedad de tipo IEnumerable, en este caso es posible modificar esta propiedad aunque sea solo de lectura. Un ejemplo:

class Program
{
	static void Main(string[] args)
	{
		MyClass myClass = new MyClass();
		((List<string>)myClass.ReadOnlyNameCollection).Add("######From Client#####");

		myClass.Print();
	}
}

class MyClass
{
	List<string> _nameCollection = new List<string>();
	public MyClass()
	{
		_nameCollection.Add("Rob");
		_nameCollection.Add("John");
		_nameCollection.Add("Jummy");
		_nameCollection.Add("Derek");
	}
	public IEnumerable<string> ReadOnlyNameCollection
	{
		get { return _nameCollection.AsEnumerable(); }
	}

	public void Print()
	{
		foreach (var item in ReadOnlyNameCollection)
		{
			Console.WriteLine(item);
		}
	}
}

En el código anterior hemos podido comprobar que la lista ha podido ser modificada cuando nuestra intención es que fuera solo de lectura. Para remediar esto podemos utilizar lo siguiente:

public IEnumerable<string> ReadOnlyNameCollection
{
	get { return _nameCollection.AsReadOnly(); }
}
10 consejos para programadores C#.Net
5 (100%) 4 votes

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;
Timeout en MySQL con Entity Framework
Valora este artículo

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).

Convertir UNIX TimeStamp a DateTime
4.5 (90%) 2 votes

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.

 

Copiar y restaurar bases de datos MySQL con codificación de caracteres intacta
Valora este artículo

Code First – Resetear Entity Framework Migrations

Si trabajas con Code First, Entity Framework y Migrations es posible que a medida que avanzas en el proyecto llegues a un estado inconsistente de la base de datos cuando intentas actualizarla con el comando update-database.

Lo ideal es solucionarlo con las opciones que te puede ofrecer codefirst, pero si aún así llegas a un punto que creas necesario resetear las migraciones lo que deberás hacer es lo siguiente:

1. – Borrar el directorio Migrations de tu proyecto.
2. – Borrar la tabla _MigrationsHistory de tu base de datos.
3. – Ejecutar el siguiente comando en la consola de administración de paquetes.

Enable-Migrations -EnableAutomaticMigrations -Force

4. – Finalmente ejecutar:

Add-Migration Initial

Todo este proceso hace que se cree un nuevo archivo Initial.cs en la carpeta de Migrations. En él podrás ver (como siempre que realizas una migración) los métodos Up() y Down() que permiten la aplicación de la migración o el regreso al estado anterior.

En este punto antes de utilizar el comando update-database deberás tener en cuenta si quieres borrar la base de datos y partir con la base de datos vacía o aprovechar los datos que ya tenías previamente.

A) Si deseas partir con una base de datos vacía será tan sencillo como borrar todas las tablas de la base de datos y ejecutar update-database.
B) Si quieres aprovechar los datos deberás profundizar en el método Up() de la migración creada y ver que tablas quieres que se regeneren. Previamente a ejecutar update-database deberás borrar las tablas que te interesan resetear en tu base de datos y comentar las líneas de código que crean las tablas que deseas conservar en el método Up(). Una vez realizadas estas dos comprobaciones podrás utilizar el comando update-database.

Espero que este artículo te haya servido de ayuda para Resetear Entity Framework Migrations.

Code First – Resetear Entity Framework Migrations
4.5 (90%) 2 votes

Múltiples columnas de identidad especificadas

Si utilizas programación CodeFirst en tu proyecto .Net es posible que al realizar una modificación en el nombre de la columna que guarda la clave de una tabla/clase/DbSet aparezca el siguiente error al utilizar update-database con alguna migración pendiente.

Multiple identity columns specified for table ‘nombre_tabla’. Only one identity column per table is allowed.

Este error indica que existen múltiples columnas de identidad especificadas, es decir, codefirst entiende que existe más de una columna clave de la tabla.

Para solucionar este problema y hacer que la migración funcione deberás reordenar la lista de operaciones en el script de migración pendiente. Deberás ubicar las operaciones de borrado (drop) primero y luego añadir la columna con la nueva clave.

public partial class RenameKey : DbMigration
{
    public override void Up()
    {
        DropPrimaryKey("dbo.nombre_tabla", new[] { "OldId" });
        DropColumn("dbo.nombre_tabla", "OldId");
        AddColumn("dbo.nombre_tabla", "Id", c => c.Int(nullable: false, identity: true));
        AddPrimaryKey("dbo.GameSummary", "Id");
    }

 

Múltiples columnas de identidad especificadas
Valora este artículo

Programar una API con ASP.NET

Como sabemos el protocolo HTTP no sirve únicamente para servir páginas Web sino que también puede actuar como APIs que exponen servicios y datos. Estos servicios pueden ser consumidos por una gran cantidad de clientes como pueden ser navegadores, aplicaciones de escritorio, etc.

Crear un proyecto ASP.NET Web API

Centrándonos un poco más en ASP.NET, con Visual Studio 2013 existe la posibilidad de crear de una manera extremadamente fácil un proyecto API. Se hará a través de una plantilla.

Web API
Nuevo proyecto Web
Web API 2
Asignar plantilla Web API a la creación del proyecto

Gracias a esta plantilla Visual Studio nos creará automáticamente un esqueleto que nos permitirá poder añadir elementos de servicio que darán funcionalidad a nuestra API. En la anterior imagen creamos un proyecto vacío pero si nos fijamos también hemos marcado más abajo que queremos que nos añada los directorios y las referencias necesarias en el proyecto.

Como siempre las cosas se pueden hacer de distintas maneras… en este caso también se puede afrontar la creación de la API con MVC. En nuestro caso continuaremos sin utilizar MVC.

Añadir  un modelo

A continuación añadiremos un modelo. El modelo es un objeto que representa los datos de tu aplicación. ASP.NET Web API puede serializar automáticamente tu modelo a JSON, XML o cualquier otro formato y entonces escribir los datos serializados dentro del cuerpo de la respuesta HTTP. Además el cliente siempre puede indicar que formato quiere fijando la cabecera en la petición del servicio.

En este ejemplo añadiremos un modelo que represente un producto. Para ello haremos click derecho encima de la carpeta Models y añadiremos una clase.

Web API Modelo

Nombraremos la clase como “Product” y escribiremos el siguiente código:

namespace ProductsApp.Models
{
 public class Product
 {
 public int Id { get; set; }
 public string Name { get; set; }
 public string Category { get; set; }
 public decimal Price { get; set; }
 }
}

Añadir un controlador

En Web API, un controlador es un objeto que maneja peticiones HTTP. Añadiremos un controlador que devuelva una lista de productos o un único producto especificado por un Identificador.

Para añadir un controlador haremos click derecho sobre el directorio “Controllers” dentro de la solución y seleccionaremos “Controller”.

Web API Controlador

En la nueva ventana elegiremos Web API Controller – Empty. Pulsaremos añadir.

Web API Controlador 2

Le podremos llamar “ProductsController” por ejemplo. Insertaremos el siguiente código dentro de este fichero:


using ProductsApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;

namespace ProductsApp.Controllers
{
 public class ProductsController : ApiController
 {
 Product[] products = new Product[]
 {
 new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
 new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
 new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
 };

public IEnumerable<Product> GetAllProducts()
 {
 return products;
 }

public IHttpActionResult GetProduct(int id)
 {
 var product = products.FirstOrDefault((p) => p.Id == id);
 if (product == null)
 {
 return NotFound();
 }
 return Ok(product);
 }
 }
}

Si nos fijamos existen 2 métodos: GetAllProducts y GetProduct. Gracias a ASP.NET Web API podremos acceder a cada uno de estos métodos a través de las siguientes URIs: /api/products y /api/products/id.

Como vemos es muy sencillo programar una API con ASP.NET. En otro post hablaremos de cómo se puede consumir un servicio de este tipo con AJAX y jQuery.

Programar una API con ASP.NET
Valora este artículo

Modelo y Base de Datos con Identity en ASP NET

Con la versión 4.5 de .NET Framework se ha incorporado la autenticación basada en Identity. Esto ya lo hablamos en pasadas entradas, ahora vamos a verlo un poquito más a fondo.

Con Identity se crean las siguientes tablas:

  • AspNetRoles
  • AspNetUserClaims
  • AspNetUserLogins
  • AspNetUserRoles
  • AspNetUsers

En estas tablas se guarda toda la información relacionada con los usuarios. Es en la tabla AspNetUsersr donde  se guardan los siguientes campos:

  • Id
  • UserName
  • PasswordHash
  • SecurityStamp
  • Discriminator

En la siguiente imagen se muestra la estructura de tablas y los campos de la tabla AspNetUsers:

Tablas con Identity en ASP.NET 4.5

Ya entrando en el código, si has generado el proyecto web con una de las plantillas que ofrece Visual Studio 2013 verás que en la carpeta “Models” se ha creado un archivo llamado “IdentityModels.cs”. En este fichero existen varias clases que definen la funcionalidad de Identity en la aplicación. Las clases son:

  • ApplicationUser. Es la entidad Usuario de aplicación. Hereda de “IdentityUser” e inicialmente está vacía aunque podemos meterle las propiedades que deseemos para personalizar nuestro modelo de usuario (http://go.microsoft.com/fwlink/?LinkID=317594). Si nos fijamos en la clase de la que hereda contiene las siguientes propiedades que se mapean a la base de datos: Id, PasswordHash, SecurityStamp, UserName así como las colecciones que relacionan con las demás tablas.

Clase IdentityUser

  • ApplicationDbContext. Es la clase que maneja el contexto Entity Framework con la base de datos. De hecho en su constructor coge el connectionstring del web.config para su conexión con la base de datos en este caso “DefaultConnection”.

Clase ApplicationDbContext

  • UserManager. Es una clase que gestiona operaciones típicas de usuarios con la base de datos. Hereda de “UserStore” y tiene diversos métodos de creación y borrado de usuarios, adicción y eliminación de roles por usuario, búsqueda por nombre o id y muchos más. También tiene gran parte de estos métodos en su modalidad asíncrona. Sin embargo desde aquí no es posible obtener todos los usuarios.
  • IdentityHelper. Esta clase estática situada fuera del espacio de nombres “Models”se encarga de sincronizar la base de datos en los registros de usuarios con el comportamiento de la aplicación en lo que se refiere a la autenticación. Cada vez que un registro de un usuario se efectúa correctamente pasará por IdentityHelper para insertarlo en la base de datos y posteriormente autenticarlo en la aplicación.

Después de analizar todo este rollo vamos a ver como podríamos obtener todos los usuarios con Identity. Si utilizamos directamente el contexto “ApplicationDbContext” accederemos a todos los usuarios mediante su propiedad “Users”:


IList<ApplicationUser> users = context.Users.ToList();

Modelo y Base de Datos con Identity en ASP NET
5 (100%) 1 vote