Reproducir sonidos del sistema en nuestra aplicación .NET 2.0

Este es un truco rápido para la tarde del sábado (estoy un poco vago), pero que seguro que a más de uno le resulta útil…


¿Te gustaría que, por ejemplo, cuando muestres un cuadro de mensaje se oiga el sonido del sistema adecuado a la situación?. Por ejemplo, lanzas un mensaje de error y que suene el sonido que el usuario tenga configurado para los errores.


En .NET 2.0 es algo realmente fácil gracias a la nueva clase SystemSounds del espacio de nombres System.Media.


Podemos escribir:



System.Media.SystemSounds.Asterisk.Play();
MessageBox.Show(«Error en la aplicación», «Se ha producido un error xxxxx, blah, blah», MessageBoxButtons.OK, MessageBoxIcon.Error);


la primera línea hace que suene el sonido predeterminado de atención, consiguiendo un diálogo aún más realista.


Los sonidos disponibles con esta clase son los siguientes: Asterisk, Beep, Exclamation, Hand y Question.

Off-topic: ¡Ya soy MCT!

Pues eso, una tontería, pero como veo que compañero en campusMVP y buen amigo Rodrigo Corral también lo ha puesto y lo hemos sacado juntos, pues yo no voy a ser menos 😉


MCT significa Microsoft Certified Trainer, es decir, profesor certificado de Microsoft. Mis competencias como profesor certificado son todas las relacionadas con las aplicaciones Web con ASP.NET 2.0 y anteriores, así como formación en los fundamentos y técnicas avanzadas de la plataforma .NET 2.0 y anteriores. Rodrigo además tiene las competencias para formar en desarrollo para Windows.


Para ello hay que sacarse una certificación completa de Microsoft antes de hacerse MCT propiamente dicho. En mi caso soy MCTS (Microsoft Certified Technology Specialist) en la plataforma .NET 2.0 así como MCPD (Microsoft Certified Professional Developer) en aplicaciones Web con ASP.NET 2.0. Estas dos son nuevas titulaciones de Microsoft y tanto Rodrigo como yo somos de los primeros en obtenerlas (de hecho Rodirgo las saco incluso cuando no estaban disponibles para el público pero Microsoft nos pidió que las hiciésemos).


La verdad es que me sorprendió lo completas que fueron las certificaciones. Sinceramente, aunque las saqué a la primera, pensé que serían más fáciles. Realmente creo que hay que controlar bastante para obtenerlas y además te piden un 70% para aprobar 🙂


Ambos esperamos que eso redunde en la calidad de la formación que impartimos en campusMVP. Ya os mantendremos al tanto a la vuelta del verano.

Creación de un control botón ASP.NET para regreso automático

Una cuestión común en todas las aplicaciones Web es hacer que la navegación sea lo más sencilla posible para nuestros usuarios. Una situación muy habitual es la de reutilizar una página para varios propósitos de modo que a ésta se puede llegar por diversos sitios. Si colocamos un botón de «Cancelar» o «Volver» es frecuente que tengamos que escribir bastante código para asegurarnos que devolvemos al usuario al lugar del que vino teniendo en cuenta los diferentes «postbacks» producidos por los controles de la página.


El siguiente control permite aislarnos de este tipo de cosas haciendo por debajo él todo el trabajo.


Añade un nuevo control de usuario y llámale «Volver.ascx». Sobre su superficie coloca simplemente un botón con el nombre cmdVolver y asígnale el texto «Volver». En el archivo de código escribe lo siguiente (en C#, en VB sería más o menos igual):


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Controles_Volver : System.Web.UI.UserControl
{
  protected void Page_Load(object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      try
      {
        this.ViewState[«referer»] = GetRefererURL();
      }
      catch { }
    }
  }

 
protected
void cmdVolver_Click(object sender, EventArgs e)
  {
    Regresar(ViewState[«referer»]);
  }

  public static string GetRefererURL()
  {
    try
    {
      return HttpContext.Current.Request.UrlReferrer.PathAndQuery;
    }
    catch 
    {
      return «»;
    }
  }

  public static void Regresar(object sURL)
  {
    try
    {
      HttpContext.Current.Response.Redirect(sURL.ToString());
    }
    catch { }
  }
}


A partir de ahora dispones de un botón para volver a la URL desde la que se llegara a la página en donde lo coloques. Tiene en cuenta que pueda ser una referencia directa y evita que Redirect «rompa» debido a alguna URL mal formada.


Para usarlo lo único que tienes que hacer es arrastrarlo sobre cualquier formulario Web y listo. Te puede ahorrar mucho trabajo repetitivo. En mi último proyecto Web con .NET 2.0 lo he usado y me ha ahorrado bastante tiempo.


NOTA: Hay que tener cuidado con el hecho de que si la página en la que lo colocas envía a otra nueva y ésta también tiene un botón de estos te uedes encontrar en un bucle cerrado. Por ejemplo, la página A enlaza con la página B que tiene un botón de regreso automático. La B enlaza a su vez con la C que también lo tiene. Si vamos de la A la B al pulsar «Volver» nos dejará en la A. Pero si vamos de la A a la B y de la B a la C, al pulsar el botón «Volver» en esta última nos deja en «B», la cual toma como referente la «C» y si pulsamos «Volver» nos dejará de nuevo en C y así en un bucle infinito ¿me he exlicado?.


Conclusión: úsalo sólo en páginas finales que no te lleven directamente a otras. Bien pensado estas deberían ser la mayoría.

Excepción con ‘ARITHABORT’ al insertar datos en una base de datos SQL Server

Este error me pasó el otro día en una aplicación que estoy desarrollando para una empresa de logística y me pareció lo suficientemente interesante como para reseñarlo aquí.


El caso es que tienes un código de actualización INSERT normal y corriente de acceso a datos, escrito directamente con código ADO.NET, a través de un procedimiento almacenado o incluso mediante el uso de un TableAdapter de un DataSet tipado (por debajo es ADO.NET normal). Cuando vas a actualziar cualquier registro, de repente, te salta el siguiente error:



INSERT failed because the following SET options have incorrect settings: ‘ARITHABORT’


Bueno. Esta excepción es el resultado resultado directo de una particularidad de SQL Server. El caso es que si tenemos una tabla que está referenciada dentro de cualquier vista de la base de datos que sea una vista indexada, no es posible introducir nuevos registros en la tabla de la manera normal y directa.


Lo típico que pasa (y de hecho fué lo que me pasó a mi): Creas varias tablas, las usas, trabajas con ellas por código etc… y todo funciona a la perfección. Cuando la aplicación ya está bastante avanzada te dices: «Vale, voy a pasar el analizador de consultas a ver qué me sugiere para mejorar el rendimiento de lo que se hace en la base de datos» (en este aplicación en concreto hay consultas bastante complejas). Pasas el analizador y te sugiere algún que otro índice, estadísticas y, a veces, también alguna vista. Aceptas las sugerencias y dejas que se hagan los cambios. Pruebas de nuevo la aplicación y ¡hop!, el maldito error reseñado arriba.


Normalmente es porque se hac creado de manera consicente o inconsciente una vista indexada que referencia a alguans tablas que ahora ya no se pueden actualziar directamente.


Una solución es evitar el uso de este tipo de vistas (la mayor parte de las veces puedes vivir sin ellas).


La solución real al problema consiste en establecer la opción:



SET ARITHABORT ON


para que se ejecute dentro del mismo conjunto de instrucciones enviadas a la base de datos (a través de la misma conexión y antes de nada). Esto permite que el INSERT en la tabla problemática tenga éxito a pesar de la vista indexada.


El códig ADO.NET que debes usar para conseguirlo es, nada más abrir la conexión  y antes de hacer la inserción el siguiente:



miConn.Execute «SET ARITHABORT ON»


Yo en mi aplicación, como no soy un experto en bases de datos y ni siquiera me gustan mucho, opté por cargarme la vista indexada 😉


Espero que esto arroje luz y le ahorre tiempo a más de uno.

Otro bug de .NET que he descubierto: valores calculados en DataSet tipados.

Este bug lo he descubierto hace poco y lo puse en su día en la página de Connect de Microsoft. El caso es que hasta la fecha nadie ha dicho «esta boca es mía», pero para mi se trata de un error claro. A continuación describo la situación así como la forma de salvarla con el menor esfuerzo…:


Una aplicación Web (imagino que en una Windows pasaría lo mismo, pero no lo he comprobado). Creas un DataSet tipado con su correspondiente TableAdapter para realizar el acceso a datos. A los campos devueltos le añades manualmente uno nuevo (o varios) que serán campos calculados a partir de los otros (por ejemplo, asignándole una expresión del tipo «Apellidos + ‘,’ + Nombre»).


Ahora pruebas el TableAdapter con la opción de vista previa y verás que, en efecto, todo va bien y la nueva columna muestra el valor calculado que se supone que debería tener.


De acuerdo… Ahora escribes código en tu aplicación que instancia el TableAdapter y llama a la versión ‘Get’ del método de acceso a datos (como sabrás hay normalmente otra por defecto que suele empezar por ‘Fill’ ¿me explico?). Resultado: el campo calculado está vacío. No funciona.


El motivo es que las expresiones que has definido para los campos calculados se asignan en el DataSet tipado mediante una llamada al método privado InitExpressions que se autogenera. Lo malo es que esta llamada la han puesto únicamente en el constructor del DataSet completo. Si usas directamente el TableAdapter para obtener y rellenar el correspondiente DataTable (lo habitual) no se llama a este método puesto que se ha instanciado directamente el DataTable, no el DataSet y luego cada uno de sus DataTable. Es fácil de entender lo que digo si te paras a pensarlo. De todos modos puedes ver el código fuente autogenerado para el DataSet tipado y sus elementos haciendo doble clic sobre él en el explorador de clases.


La mejor solución es instanciar el DataSet (se llama al constructor, claro) y luego usar el método ‘Fill’ para llenar la tabla adecuada. Con esto se soluciona pero es un poco «peñazo». Además debería dar el mismo resultado instanciando el DataTable desde ‘Get’. Cada DataTable debería tener su propio InitExpressions particular en el constructor, en lugar de un único para todo el DataSet. ¿No?


En fin, que si alguna vez usas expreiones calculadas en un DataSet tipado y no te funcionan ya sabes por donde van los tiros y como solucionarlo.

Comportamiento extraño con el formato de fechas en los GridView

Cuando estamos usando un GridView para mostrar datos obtenidos de una base de datos resulta muy cómodo usar el editor de columnas para definir cómo se deben mostrar los datos en el listado que se genera.


Una propiedad muy interesante de las columnas enlazadas en DataFormatString, que nos permite decidir qué estilo queremos aplicar a las columnas.


Sin embargo con los campos que contienen fechas pasa unacosa muy rara…


Si tenemos un campo que es una Fecha y definimos una columna enlazada de modo similar a este:



<asp:BoundField DataField=«FechaFin» DataFormatString=«{0:d}» HeaderText=«Final»>


esperaremos ver algo similar a lo siguiente en la columna: 13/7/2006.


Sin embargo por más que cambiemos el formato veremos algo como esto: 13/7/2006 00:00:00


Es decir, no hace caso y mete el formato de fecha y hora cortas.


Si queremos que una columna de tipo fecha haga caso al formato tenemos dos soluciones:



1.- Convertirla en una plantilla. Con esto funcionará sin problemas el formato.


2.- Usar el atributo HtmlEncode con el valor ‘false’, así:



<asp:BoundField DataField=«FechaFin» DataFormatString=«{0:d}» HtmlEncode=«false» HeaderText=«Final»>


Con este último conseguiremos el resultado esperado.


Este problema puede volver loco a más de uno ya que no es nada obvio. Así que espero que os sirva de algo 🙂


NOTA: Explicación de este efecto a raíz del requerimiento de un lector…


Aquí está el código del método FormatDataValue de la clase BoundColumn que es el que se encarga de renderizar el contenido de la celda (extraido con NetReflector):


protected virtual string FormatDataValue(object dataValue, bool encode)
{
  string text1 = string.Empty;
  if (!DataBinder.IsNull(dataValue))
  {
    string text2 = dataValue.ToString();
    string text3 = this.DataFormatString;
    int num1 = text2.Length;
    if ((num1 > 0) && encode)
    {
      text2 = HttpUtility.HtmlEncode(text2);
    }
    if ((num1 == 0) && this.ConvertEmptyStringToNull)
    {
      return this.NullDisplayText;
    }
    if (text3.Length == 0)
    {
      return text2;
    }
    if (encode)
    {
      return string.Format(CultureInfo.CurrentCulture, text3, new object[] { text2 });
    }
    return string.Format(CultureInfo.CurrentCulture, text3, new object[] { dataValue });
  }
  return this.NullDisplayText;
}


Si te fijas, cuando se escoge la opción de formatear el contenido (HtmlEncode = true, valor por defecto), el valor de codificación se obtiene de la representación de texto del valor (text2, que si te fijas arriba es dataValue.ToString(). Esto hace que en el caso de las fechas el valor tenga al final la hora también, con lo que en el último condicional se usa para dar formato al texto. Si desactivas la codificación la cadena para la celda se genera directamente desde el valor del dato con el formato especificado, sin pasarlo a texto antes.


Para mi esto es un «bug» que deberían corregir porque se debería obtener el mismo resultado por los dos caminos.

EyeOS: Sistema operativo Web

eyeOS v0.9 IRIS


Leo en el Blog de Carlos Fouz de la existencia de este proyecto originado y soportado fundamentalmente en España (en Barcelona) sobre un «Sistema Operativo» Web.


Se trata de una aplicación Web 2.0 escrita en PHP 4 que va un poco más allá de Netvibes o Windows Live para simular el modo de uso y ciertas utilidades típicas de un sistema operativo. Ofrece un escritorio y diversas aplicaciones a través de un lanzador que podemos utilizar desde cualquier navegador. Tiene un editor de textos, una calculadora, anotaciones, agenda, calendario, juegos, etc… Incluso cosas tan peregrinas como ¡un navegador Web!. Cuando lo vi la verdad es que me hizo mucha gracia: un navegador simulado dentro de otro navegador… NO me digas que no tiene coña 😉



En fin, el caso es que es gratuito y merece la pena echarle un vistazo.


 


Ahora va bastante lento y tiene algunos fallos pero todavía es una beta. Aún así pruébalo…


Por otro lado se puede descargar el código fuente y un instalador para montar tu propio servidor de EyeOS y hacer hosting del producto para otra gente, lo cual no está mal.


Una pregutna que yo me hago: ¿cuánto trabajo costaría hacer una aplicación similar usando ASP.NET 2.0 y Atlas?. Yo creo que relativamente poco, sobre todo si nos poderas el trabajo que les tiene que haber dado a estos hacerlo en PHP. Sólo de pensarlo me entran sudores fríos 😉


Si alguien se anima ha hacer su propio WebOS con ASP.NET 2.0 y Atlas ¡por favor decídmelo y hacédemlo llegar!.

Ya soy persona: ya vuelvo a tener Internet :-)

Los que seguís este Blog asiduamente habréis notado que durante el último mes apenas he publicado nada. El motivo es que he estado «castigado» sin conexión en casa, y desde la oficina no suelo tener tiempo para pensar siquiera en publicar algo aquí 🙁


La historia de todos modos es rocambolesca y además me apetece contarla para que no pille a otros por sorpresa…


Mi proveedor de acceso en casa es Wanadoo. El caso es que empecé a trabajar con ellos hace tiempo con un ADSL de 512 Kbps que para el momento estaban muy bien. Poco después movieron su oferta de velocidad a 2 Mbps, lo cual me llenó de alegría porque tenía el cuádrupe de velocidad por el mismo precio. El cambio se hizo sin problemas y de forma automática. Además la línea iba muy bien (a 1,6 o 1,8 Mbps normalmente).


El caso es que hace un mes vi que por el mismo precio ahora ofrecían 20 Mbps y me dije que sería estupendo aumentar la velocidad. Como de este tipo de compañías no me fío ni un pelo (bueno, mejor dicho, no me fio de la gente que ponen para dar atención telefónica) llamé dos veces en días distintos para preguntar lo mismo y que dos personas diferentes me lo corroboraran. La pregunta era muy simple: «Si me cambio de 2 Mbps a 20 Mbps ¿se me cortará la conexión en algún momento? ¿Tendré días sin servicio?». Respuesta en ambos casos: «No señor, en absoluto. el cambio es automático y se interrumpirá un momento únicamente la conexión, pero nada más».


Bueno, pues si dos de estas personas me decían lo mismo es que no debería haber problema ¿verdad?. Así que le dije al último (era un tio) que, adelante, que me solicitasen el cambio a 20 Mbps: «De acuerdo señor, en dos días aproximadamente se producirá el cambio y disfrutará de una velocidad mayor».


¡Perfecto!. Iluso de mi….


Al cabo de dos dias, en efecto, me quedo sin conexión. Pasan varios minutos y siguo sin conexión por lo que llamo a Wanadoo a que me expliquen si hay algún problema. ¿Qué pasaba?…


… pues que el h@~d#p&ta del operador que me había atendido, en lugar de solicitarme un CAMBIO de velocidad, como no debia saber hacerlo (o le faltaba alguna neurona), lo que hizo fué solicitarme ¡¡¡¡una BAJA y un ALTA de una nueva línea!!!! Para flipar.


El caso es que aunque la baja y el alta sean dentro de la misma empresa el cambio tarda lo mismo que si me cambiara de compañía, por lo que, sin otro remedio, sólo me quedaba el derecho a pataleo (que, creedme, ejercí). Así que, hala, a esperar entre 5 y 6 semanas sin conexión.


Encima es que son idiotas: me han mandado un router ADSL nuevo (que pasa a engordar mi colección porque no lo necesito) por mensajería urgente, es decir han multiplicado sus costes. Y encima como ahora no tienen compromiso de permanencia puedo quedarme este mes si quiero y agenciarme el router (cosa que no haré, no quiero estar otras 6 semanas sin conexión).


Pero ahora viene lo peor de todo y lo más paradójico de la situación: Me he cambiado para tener 20 Mbps y en cuanto tuve conexión hace un rato he hecho unas cuantas pruebas de velocidad ¡¡¡ Y NO PASO DE 1,2 Mbps EN NINGÚN CASO!!.


Es decir, he estado sin conexión para, encima, al final tener como resultado ¡¡¡una velocidad inferior!!!.


En fin, para reir por no echarse a llorar.


Por lo menos ahora vuelvo a tener conectividad y en breve retomaré con fuerza el blog para publicar cosas interesantes de .NET en general y sobre todo de ASP.NET, así que permanece al tanto 🙂