Expression Web Designer y la codificación UTF-8

Hay una cosa de Expression Web Designer que me molesta un montón, y es que por defecto guarda todas las páginas HTML con codificación UTF-8. Esto se me pega con otros programas que uso y además puede provocar problemas en algunos programas ya que esta codificación mete una marca de ordenación de bytes (BOM o Byte Order Mark) para distinguir la plataforma en la que se generaron. Es por este motivo que a veces al visualizar ciertas páginas, incluso páginas de servidor, éstas aparecen con unos caracteres extraños delante () muy molestos. En concreto en e-mail marketing que es fundamentalmente para lo que lo utilizo yo da muchos problemas.


Por defecto Expression Web genera los archivos HTML así. Cuando editamos una página y no está especificada explícitamente en la página la codificación a utilizar siempre las guarda como UTF-8. Podemos cambiar este comportamiento por defecto si vamos a las «Herramientas·Opciones del editor» y lo ajustamos así:



El problemilla es que cuando creamos páginas desde cero con Expression Web éstas están codificadas con UTF-8 de todos modos.


Para solucionarlo podemos hacer un cambio en el sistema de plantillas que utiliza. Para ello vamos a la carpeta «C:Program FilesMicrosoft ExpressionTemplates1033PAGES12normal.tem». Ésta contiene un archivo de plantilla «normal.htm» que es el que se usa para crear las nuevas páginas:



Antes de modificarlo le sacamos una copia por si acaso (normal.bak en la figura). Si lo abres con el bloc de notas de Windows, verás que contiene el siguiente HTML:



Bórrale el x-undefined resaltado en la figuyra y además cambia el charset de utf-8 y haz que quede así:



<meta http-equiv=»Content-Type» content=»text/html; charset=windows-1252″ />


Ahora vete a «Archivo·Guardar como» y guárdalo asegurándote de que utilizas la codificación ANSI, así:



¡OJO!, con los permisos por defecto de esa carpeta no te dejará sobrescribir el archivo desde el bloc de notas, así que guárdalo con elmismo nombre en otro sitio (por ejemplo en mis documentos) y luego copialo desde el explorador de Windows sobre el archivo original.


¡Ya está! a partir de ahora no te dará más problemas conla codificación.


Puedes hacer el mismo cambio en otros tipos de archivos, como por ejemplo los ASPX, buscando la plantilal corresponsdiente en esa carpeta.

Cómo enviar correo electrónico por código usando cuentas de GMail

Enviar correo electrónico desde código .NET usando un servidor SMTP es muy fácil gracias al uso de la clase System.Net.Mail.MailMessage.


Un servidor SMTP normal trabaja a través del puerto 25 y sólo necesitaremos tener unas credenciales válidas en el mismoq ue nos permitan enviar correo. Lo habitual en una aplicación cualquiera es usar el servidor SMTP de nuestra cuenta de correo favorito con esta técnica sin problemas.


Pero ¿qué pasa si nuestra cuenta de correo es de GMail? Pues que la técnica convencional no funcionará. El motivo es que GMail usa un puerto diferente y además precisa el uso de una conexión cifrada con SSL para seguridad, por lo que el código normal que vas a encontrar por ahí no te servirá.


¿Qué puedo hacer entonces?


La clase SmtpClient nos ayudará para conseguirlo. Básicamente se trata de indicarle un par de parámetros extra para indicar el puerto a utilizar y la obligatoriedad de SSL. Lo demás lo hará esta clase por nosotros.


El siguiente código en C# ilustra un ejemplo de cómo enviar un correo de prueba a través de GMail usando una aplicación de consola:


using System;
using System.Collections;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;

public class EjemploCorreoGMail
{
    public static void Main()
    {
            System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
            msg.To.Add(«destinatario@dominio.com»);
            msg.From = new MailAddress(«micuenta@gmail.com», «Tu Nombre», System.Text.Encoding.UTF8);
            msg.Subject = «Prueba de correo a GMail»;
            msg.SubjectEncoding = System.Text.Encoding.UTF8;
            msg.Body = «Cuerpo del mensaje»;
            msg.BodyEncoding = System.Text.Encoding.UTF8;
            msg.IsBodyHtml = false

            //Aquí es donde se hace lo especial
            SmtpClient client = new SmtpClient();
            client.Credentials = new System.Net.NetworkCredential(«micuenta@gmail.com», «miclave»);
            client.Port = 587;
            client.Host = «smtp.gmail.com»;
            client.EnableSsl = true; //Esto es para que vaya a través de SSL que es obligatorio con GMail
            try
            {
                        client.Send(msg);
            }
            catch (System.Net.Mail.SmtpException ex)
            {
                        Console.WriteLine(ex.Message);
                        Console.ReadLine();
            }
    }
}


 

Cómo colocar un icono para indicar la ordenación en la cabecera de un GridView

Esta pregunta surge muchas veces en cursos y conversaciones técnicas varias. La cosa es la siguiente: tengo una rejilla (GridView) de ASP.NEt 2.0 en un formulario ASPX, y he activado las opciones de ordenar sus columnas, de modo que cuando pulso sobre una cabecera logro de manera automática la ordenación por el campo correspondiente. Es estupendo pues no tengo ni que escribir código para lograrlo, al contrario de lo que pasaba al usar un DataGrid en ASP.NET 1.x.


Pero… ¿Qué pasa si quiero evidenciar de un modo más claro cuál es el orden concreto de mi rejilla?


Lo típico es colocar un iconito con una flecha hacia arriba o hacia abajo en la cabecera adecuada para indicarlo, algo así:




(Fíjate en el iconito al lado de «Nombre» que indica el orden inverso)


Pero ¿cómo lo consigo?


Hay que responder adecuadamente al evento RowCreated de la rejilla.


Antes de nada asegúrate de tener un par de iconos para las flechas de ordenación. En mi caso los he colocado en la carpeta «Imgs» de la raíz de mi aplicaicón y les he llamado sort_asc.gif y sort_desc.gif.


Ahora en tu rejilla responde al evento RowCreated de la siguiente manera (en C#):


protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
  GridView grd = (GridView)sender;

  if (e.Row.RowType == DataControlRowType.Header)
  {
    foreach (TableCell tc in e.Row.Cells)
    {
      if (tc.HasControls())
        {
          // Buscar el enlace de la cabecera
          LinkButton lnk = tc.Controls[0] as LinkButton;
          if (lnk != null && grd.SortExpression == lnk.CommandArgument)
            {
              // Verificar que se está ordenando por el campo indicado en el comando de ordenación
              // Crear una imagen
              System.Web.UI.WebControls.Image img = new System.Web.UI.WebControls.Image();
              // Ajustar dinámicamente el icono adecuado
              img.ImageUrl = «~/imgs/sort_» + (grd.SortDirection == SortDirection.Ascending ? «asc» : «desc») + «.gif»;
              img.ImageAlign = ImageAlign.AbsMiddle;
              // Le metemos un espacio delante de la imagen para que no se pegue al enlace
              tc.Controls.Add(new LiteralControl(» «));
              tc.Controls.Add(img);
            }
         }
       }
     }
   }


Veamos lo que se hace:


Primero se convierte el argumento genérico sender en una referencia a una rejilla. De este modo obtenemos una referencia a la rejilla que ha lanzado el evento y el mismo método nos puede servir para colocar el icono en todas las rejillas de la misma página (por supuesto podemos ir un poco más allá y colocar este manejador en un módulo en App_Code y reutilizarlo para toda la aplicación).


Acto seguido comprobamos si el elemento que se está creando es una cabecera de la rejilla o no puesto que este evento se lanza para todas las filas de la misma, y sólo nos interesan en este caso las cabeceras.


Una vez que estamos seguros de estar trabajando con la fila de la cabecera recorremos todas sus celdas en busca de controles de tipo LinkButton. Sólo las celdas de la cabecera de campos por los que está permitido ordenar tienen un control de este tipo (sobre el que pulsamos para conseguirlo). Las demás tienen simples etiquetas Label. Es decir, si hay un LinkButton es que esa celda permite ordenación. Además dicho control estará de primero (y único) en la celda.


Por lo tanto sólo nos resta comprobar si además de permitir la ordenación estamos en la celda concreta, es decir, en la celda por la que se está ordenando actualmente la rejilla. ¿Cómo lo sabemos?


Cuando la rejilla se ordena se establece automáticamente su propiedad SortExpression con el nombre del campo de la columna por la cual estamos ordenando. Éste nombre se obtiene precisamente de la propiedad CommandName del enlace de la cabecera correspondiente. Por lo tanto si el comando asociado con el enlace que estamos comprobando coincide con el campo de ordenación actual de la rejilla, ¡esta es nuestra cabecera!.


Por fin, si estamos en la cabecera correcta sólo tenemos que introducir la imagen, que es justo lo que se hace en el último trozo de código y que está explicado con comentarios: se crea una imagen, se le asocia el icono correspondiente a la dirección de ordenación y se añade al final de la celda actual con un espacio por el medio para separarlo del enlace.


¡Listo!


Espero que te resulte útil.

Nuestro nuevo curso de certificación en Administración y Mantenimiento de Windows Server 2003

Lo estabas necesitando - Curo oficial Windows 2003


Sí, ahora también en campusMVP, un curso dirigido a los chicos de sistemas.


¿Acaso los de Home English no enseñan ahora francés también?, pues nosotros aparte de programación… también sistemas :-))


Este curso está dirigido a todos aquellos profesionales TIC que trabajan en entornos de administración de sistemas cliente (Windows XP) y quieren progresar en su carrera hacia la administración y mantenimiento de redes complejas de empresas medianas o grandes con Windows Server.


Al acabar la formación sabrás todo lo que necesitas para gestionar y resolver problemas en una infraestructura de ordenadores basada en Windows Server 2003.


Con este curso, creado por el MVP Juansa Llopis, podrás preparar a tu ritmo y desde cualquier sitio el examen 70-290 de certificación en Windows Server 2003.


Además, si eres un trabajador en activo de una empresa española te gestionamos la bonificación con el Estado para que el curso te salga realmente barato.


Ya no tienes disculpa… Aprovecha este verano para convertirte en Microsoft Certified Professional (MCP) en Windows 2003.


¡Comienzo el 2 de Julio!  


¡LOS 40 PRIMEROS MATRICULADOS RECIBIRÁN UN DESCUENTO DE 100 EUROS POR CORTESÍA DE Technet!


Toda la información aquí

Otro motivo más por el que molan mucho estos tíos de Google: GMail Theater

Lo reconozco: es una debilidad la que tengo por Google. Y más desde que estuve en sus instalaciones de visita  a principios de año. Yo mismo lo reconocía: «Si no fuese Google esto serían unas oficinas normales. Chulas, pero normales». Pero es que el ambiente «cool» que se respira, esas salas de juegos, esos «peacho» monitores giratorios que les ponen, la comida, los cuadros en los pasillos… es tan guay :-))


Y no me digáis que el marketing que hacen, aparentemente ingénuo, no mola un montón. El último ejemplo: GMAil Theater. Bue-ní-si-mo. Y no parece que se hayan gastado mucha pasta:





Si a alguien le quedaban dudas de usar GMail (a mi no, desde luego, he sido usuario acérrimo desde que se vendían las primeras invitaciones en eBay por una pasta), este tipo de cosas seguro que las despeja 🙂


Y es que, oye, aparte de Microsoft también hay otra gente que hace las cosas bien generalmente 😉


(antes de que alguno me acribille a comentarios chorras, nótese el tono irónico de la frase anterior)

Errores al recompilar aplicaciones ASP.NET 2.0 y cómo solucionarlos

Una cosa típica que pasa en VS2005 desde que salió es que estamos trabajando en una aplicación, cambiamos algo en el código, la lanzamos para probar, paramos, y así sucesivamente y, de repente, en un momento determinado y sin venir a cuento, nos aparece un mensaje de error y nos dice que no se ha podido compilar porque un archivo estaba bloqueado o algo así (he intentadno reproducir una captura, pero justo hoy no está por la labor y me funciona perfectamente).


El caso es que suelen ser mensajes estilo:



Could not load file or assembly ‘XXXXXXX’ or one of its dependencies. The system cannot find the file specified.


aunque hay algunos más.


Este error se produce porque hay algunos archivos resultantes de la anterior compilación que quedan bloqueados y el entorno no puede sobrescribirlos.


Hay varias soluciones:



1.- Compilar entero el proyecto otra vez desde el menú Build·Build all. Es lo que suelo hacer yo.
2.- Borrar los archivos temporales de ASP.NET. Es fácil de hacer ocn un bat que tengamos siempre a mano.
3.- Meter un ajuste en web.config para indicar al compilador que no use compliación por lotes, así:

<compilation debug=»false» batch=»false»></compilation>

No me preguntes porqué funciona, pero el caso es que funciona.


Puedes encontrar los detalles de este tipo de error y esta última solución en este artículo de la Knowledge base de Microsoft.


El caso es que la gente de Microsoft ha sacado un parche no oficial para solucionar este problema. Instálalo sólo si te pasan estas cosas. Lo puedes descargar desde aquí. Necesitas autenticarte con una cuenta Passport para descargarlo, pero es libre y gratuito.


Espero que te sirva.

Creación de tablas de proveedores ASP.NET desde línea de comandos

Como muchos programadores de ASP.NET saben (y también se ha comentado aquí en otras ocasiones) en la carpeta «C:WindowsMicrosoft .NETFrameworkv2.0.xxxx» existe un ejecutable, aspnet_regsql.exe, que permite crear la estructura de tablas necesarias por ASP.NEt para almacenar la información de sus proveedores en SQL Server. Sirve tanto para SQL Server 2005 como para versiones más antiguas, como la 2000.


La estructura de tablas creada sirve para almacenar todo tipo de información implementada mediante proveedores de tipo «SQLProvider» que vienen con ASP.NET: autenticación y autorización (usuarios y roles), perfiles, Webparts, sesiones, eventos, configuración y mapas de sitios.


Podemos lanzar ese ejecutable para obtener un sencillo asistente gráfico que nos permitirá crear esta estructura de tablas y procedimientos almacenados en cualquier base de datos. Pero además podemos ejecutar aspnet_regsql.exe desde la línea de comandos para crear esta estructura automáticamente durante las instalaciones o bien para obtener un mayor control sobre el proceso como veremos enseguida.


Una de las cosas más interesantes de usar aspnet_regsql.exe desde la línea de comandos y no en modo gráfico es que nos permite obtener un control mucho mayor sobre lo que vamos a crear. Por ejemplo, si nuestra aplicación no utiliza webParts ni otras cuestiones avanzadas y sólo queremos gestionar usuarios (pero no roles) con Membership ¿para qué vamos a crear todas las tablas y procedimientos?. Podemos escribir en este caso lo siguiente:



aspnet_regsql.exe -S miSQLServer -E -d MiBD -A m


¿Complicado? ¡Que va! Sólo hay que conocer los parámetros.


La línea de comandos nos da muchas más opciones de control. Si escribimos aspnet_regsql.exe -? obtendremos una lista completa. Las más interesantes son:



– S <servidor>: permite especificar el servidor con el que conectarse.
– E: indica que se deben usar las credenciales de Windows actuales para conectarse.
– U <usuario>: si preferimos especificar un inicio de sesión de SQL Server podemos introducir el nombre de usuario.
– P <clave>: idem que el anterior para la contraseña.
– d <base de datos>: nombre de la base de datos a usar dentro del servidor.
– C <cadena con>: si lo preferimos introducimos una cadena de conexión normal y no tenemos que usar todo lo anterior.
– A: agrega una función de proveedor a la base de datos. Podemos especificar ‘all’ para que meta todas o una de la siguiente lista para algo parcial como en el ejemplo:



m: Membership
r: Roles
p: Profile
c: Personalización
w: eventos


Si queremos indicar ma´s de una basta con escribirlas seguidas: -A mrp.
– R: esta sirve para retirar funcionalidades si es eso lo que queremos. Tiene las mismas opcioens que el anterior.
-sqlexportonly <archivo>: Si indicamos esto se genera un script SQL para crear las opciones elegidas, pero no se envía a ninguna base de datos. Útil para meterlo en nuestra propia rutina de inicalización.


Esta última opción de generar el script en un archivo es quizá la menos conocida pero a la vez la más útil de todas.


Existen una serie de parámetros adicionales que se usan sólo para trabajar con la caché de SQL en versiones antiguas de SQL Server (7.0 y 2000).


Espero que lo encuentres útil.

CampusMVP saca la convocatoria de verano de sus cursos :-)


























 
 
 










Feed your brain -  este veranocampusMVP - 902 876 475


campusMVP – Nueva convocatoria de cursos


¿Qué mejor momento para ponerte al  día en .NET que la época estival? La oficina está más tranquila, el jefe se irá de vacaciones y seguro que tienes algunas horas sueltas aunque quien disfrute de vacaciones seas tú.


Eso hemos pensado en campusMVP y, por primera vez, ofrecemos una convocatoria de verano de todos nuestros cursos, incluidos los de certificación.


Para ello, además, hemos remodelado la oferta existente con unos precios menores en casi todos los cursos y descuentos interesantes si eres antiguo alumno o estudiante universitario.


Recuerda que puedes formarte a tu ritmo y desde cualquier lugar, hasta desde ese chiringuito wi-fi de la playa que, como buen friki, seguro que adoras. ¡Nosotros también! 🙂


Los cursos de certificación comienzan el día 18 de Junio, aunque te puedes matricular hasta el día 30 si prefieres. Tienes hasta el 30 de septiembre para hacerlos. 

Los cursos normales son de convocatoria abierta
, así que puedes comienzar hoy mismo. Dispones de 1 mes para cursos sueltos o 2 meses si te matriculas de un ‘pack’ completo.


 


 








Cursos de certificación


Las certificaciones oficiales de Microsoft te ayudarán  a mejorar tu carrera. Nuestra formación específica te habilitará para certificarte rápidamente.


Certificación


 Cursos on-line


Nuestros cursos on-line te permiten crear una formación a la carta para mantenerte al día de las últimas tecnologías para el desarrollo de Microsoft. Construye tu formación a medida.


Cursos on-line


Libros y material oficial


Compra directamente en campusMVP nuestros libros de desarrollo. También puedes pedirnos cualquier MOC y otros materiales oficiales de Microsoft.


Libros

 
 

















Powered by MAILCast

Añadido a mi post "Obtener la IP de conexión de un usuario (aunque entre con un proxy)"

Respecto a mi post anterior «Obtener la IP de conexión de un usuario (aunque entre con un proxy)» voy a hacer un añadido a raíz de una pregunta que me han hecho, que aunque la contesté en lso comentarios del mismo, prefiero ponerlo aquí porque mucha gente lee este blog a través de su copia en Geeks en lugar de directamente en www.jasoft.org.


La pregunta en concreto era:



Esa cabecera Header, HTTP_X-Forwarded-For, aparece documentada oficialmente ? ¿Es parte del HTTP 1.1, es decir, aparecería en todas las peticiones a páginas que se hicieran (htm, aspx, asp, …) ?


La respuesta:



La cabecera X-Forwarded-For estaba en los primeros borradores del RFC 2616 para HTTP 1.1 pero luego lo quitaron.
Sin embargo el proxy más utilizado de Internet (Squid) lo utilizó desde el principio y se ha quedado como estándar de facto.


De hecho la RFC 2616 indica otra cabecera para estos menesteres llamada «Via» (está en la sección 14.45 del RFC), pero curiosamente no proporciona ninguna forma estándar de indicar la dirección IP y su uso es prácticamente nulo, así que normalmente usarás la cabecera que indico pues es la que te vas a encontrar.


El Proxy-caché de Teléfonica, por ejemplo, usa esta cabecera y te servirá sin problemas para determinar la IP original del usuario.


Espero que esto le sirva a alguien.

Obtener la IP de conexión de un usuario (aunque entre con un proxy)

El otro día me hicieron una pregunta muy común que es «¿cómo puedo obtener la dirección IP de los usuarios que se conectan a mi aplicación Web ASP.NET?»


La respuesta es directa y sencilla: usando la variable HTTP_CLIENT-IP de las cabeceras del servidor, a través del objeto Request así:



Request.ServerVariables{«HTTP_CLIENT-IP»]


Más fácil imposible.


Sin embargo hay una cuestión que no todo el mundo tiene controlada y es que muchos usuarios acceden a Internet a través de un proxy, y la mayor parte de las veces ni siquiera lo saben. Ello es debido a que algunos proveedores de acceso a Internet (por ejemplo Telefónica en España) para ahorrar ancho de banda utilizan proxies-caché que actúan de hombre en el medio a la hora de acceder a las páginas de Interenet. Si no lo tenemos en cuenta podemos llevarnos más d eun disgusto en nuestras aplicaciones, sobre todo si creemos que con la cabecera anterior ya tenemos la IP del usuario, ya que en realidad obtendremos la IP del Proxy.


¿Cómo obtenemos entonces la verdadera dirección IP del usuario?


Pues también muy fácil, aunque hay que saberlo, claro 🙂 Hay que consultar otra cabecera y ver si contiene algún valor. Se trata de HTTP_X-Forwarded-For, así:



Request.ServerVariables(«HTTP_X-Forwarded-For»)


Así, por ejemplo, la siguiente página (a pelo, directamente el código en ella) nos sirve para indicar si un usuario accede a través de un proxy o no y cuáles son las IPs que intervienen en el proceso:



IP que hace la petición: <%= Request.ServerVariables(«REMOTE_ADDR») %>
<br>
<%
Dim ClientIP, Forwaded, RealIP


RealIP = «»


ClientIP = Request.ServerVariables(«HTTP_CLIENT-IP»)
If ClientIP <> «» Then
 RealIP = ClientIP
Else
 Forwaded = Request.ServerVariables(«HTTP_X-Forwarded-For»)
 If Forwaded <> «» Then RealIP = Forwaded
End If


If RealIP <> «» Then
 Response.Write(«El usuario está accediendo a través de un Proxy. Su verdadera dirección IP es: » + RealIP)
End If
%>


Por cierto: esta página tiene una particularidad y es que si cambiamos su extensión a .asp o a .aspx funcionará tanto en ASP clásico como en cualquier versión de ASP.NET.


Espero que a alguien le resulte de utilidad 🙂