Blog de tecnologia y desarrollo.

Seleccionar el texto de un Textbox en ASP.Net

November 15th, 2007

Ahora que estoy entendiendo el paradigma de ASP.Net (cuando lo conoci me confundi mucho pues no era como trabajar con ASP tradicional pero tampoco como trabajar con windows forms) le estoy tomando mucho cariño.

Un Textbox en ASP.Net no tiene una propiedad o metodo definido para seleccionar el texto dentro de el. Pero no hay problema, por que podemos usar el querido y confiable Javascript para ello.

Una forma sencilla de lograr esto es mediante el uso del metodo Attributes.Add() de nuestra caja de texto. Basta poner el siguiente codigo en el Load del codebehind de nuestra forma:

TxtBusqueda.Attributes.Add("onfocus", "SetSelected();");

Con esto, a la hora de “renderear” nuestro control, en la declaracion veremos algo como esto:

<input name="TxtBusqueda" type="text" ... onfocus="SetSelected();" />

Como vemos, agregamos ese atributo a nuestra caja de texto. Ahora, solamente hay que escribir en el HTML de nuestra forma el codigo adecuado:

<script type="text/javascript">
function SetSelected()
{
document.form1.TxtBusqueda.select();
}
</script>

Como vemos, esto puede ser muy util pues podemos controlar finamente el comportamiento de cualquier control, pudiendo agregar, por ejemplo, comportamiento para otros eventos, asi como atributos que no forman parte de nuestros controles ASP.Net ∞

SOAPopera: Publicando un web service I

September 25th, 2007

Una de los “ultimos” gritos de la moda en cuanto al desarrollo, son los web services. En lo particular, me parecen una tecnologia excelente, por que permiten “consumir” servicios ya construidos sin preocuparte de la plataforma en la que esten construidos. Para muchas aplicaciones, una arquitectura basada en servicios Web puede ser el santo grial… si lo sabes utilizar correctamente.

Hace poco en mi trabajo (empresa X), surgio la necesidad de que la empresa Y trabajara con algunos de nuestros datos para una validacion en una aplicacion propia. Por politicas de X, esta prohibido liberar a externos cualquier base de datos. De manera que necesitabamos que la aplicacion hecha por Y consultara los datos de X sin tener acceso real a los datos… parecia un caso perfecto para los WebServices.

Como buen .Netero, se que es muy facil construir un WebService en VS. De hecho, tengo algunos trabajando en la red interna, sin problemas (notes que dije red interna). Esa es mi experiencia con ellos, asi que sabia que construir un simple WebService que consultara una base de datos y regresara una cadena, no seria problema alguno.

Y no lo fue. Las pruebas estuvieron bien, el servicio parecia que hacia lo que tenia que hacer. Publicamos, y todo bien, de nuevo probe y todo funcionaba bien. Incluso hice un pequeño ejecutable que lo consumia, y de nuevo, todo sin problemas.

Pero a la hora de pedirles a los usuarios que lo probaran, simplemente no se podian conectar. Descartamos tullidez de su parte por que en esta pagina (muy buena para las pruebas, por cierto) tampoco estaba funcionando, asi que el problema caia en mi cancha.

Me pase largas y tediosas horas tratando de decifrar la solucion, pero, al menos ese dia, no lo logre. Despues de mas de 10 horas de cambiar el codigo sin exito comienzas a alucinar, asi que decidi que seria mejor continuar al dia siguiente con la cabeza mas fresca.

Al dia siguiente, inmediatamente note algo extraño (descansar ayuda). La pagina de pruebas de SOAP leia correctamente el WSDL, pero luego, buscaba la funcion en una direccion mas o menos asi:

http://192.168.1.100/servicio/funcion.asmx

En lugar de buscarla en:

 http://empresaX.com/servicio/funcion.asmx

No habia notado nada raro hasta que cai en la cuenta de que la direccion 192.168.x.x es una IP local, no publica. Al leer el WSDL, en efecto, encontre la causa del problema

<wsdl:port name=ServicioSoap binding=tns:ServicioSoap>

<soap:address location=https://192.168.1.100/servicio/funcion.asmx />

</wsdl:port>

El problema radicaba en que el WSDL (que es automaticamente generado), estaba tomando la IP de la maquina en la que residia (lo cual estaria bien si estuviera directo a internet, pero al estar detras de un Router, la cosa se ponia diferente). De manera que en realidad el WSDL hacia que la aplicacion preguntara por una servicio en una direccion que jamas encontraria.

Dar con el problema fue casi tan dificil como dar con la solucion. En mis busquedas practicamente todos compartian el problema, pero ningun la solucion. Encontre muchas soluciones que no funcionaban o no me convencian. Hasta que llege al benito blog de Kirk Allen Evans, donde habia una solucion para un problema similar.

El chiste aqui es  crear una clase derivada de SoapExtensionReflector que nos permitira hacer cambios en el WSDL en tiempo de ejecucion. Debe verse algo asi:

namespace EmpresaX.ServicioWeb
{
    public class LocalAddressReflector : SoapExtensionReflector
    {
        public override void ReflectMethod()
        {
            
        }

        public override void ReflectDescription()
        {
            ServiceDescription description = ReflectionContext.ServiceDescription;
            foreach (Service service in description.Services)
            {
                foreach (Port port in service.Ports)
                {
                    foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
                    {
                        SoapAddressBinding binding = extension as SoapAddressBinding;
                        if (null != binding)
                        {
                            binding.Location = binding.Location.Replace
				(Properties.Settings.Default.LocalAddress, Properties.Settings.Default.PublicAddress);
                        }
                    }
                }
            }
        }
    }
}

Properties.Settings.Default.LocalAddress y PublicAddress no son mas que valores en el archivo de configuracion que corresponden a las direcciones local y publica del servicio. Lo deje en el archivo de configuracion para no tener que recompilar la aplicacion si estas direcciones cambiaban.

Despues, en el archivo de configuracion, En la seccion de Configuration/System.Web hay que agregar lo siguiente (para asegurarnos que nuestra clase sea cargada).

<webServices>

<soapExtensionReflectorTypes>

<add type=EmpresaX.ServicioWeb.LocalAddressReflector, WebService/>

</soapExtensionReflectorTypes>

</webServices>

Cabe destacar que el nombre “localAddresReflector” lo puedes reemplazar por el que tu hayas elegido para tu clase, y que “WebService” no es mas que el nombre del folder (en este caso, raiz) donde se encuentra mi clase (sin eso, no funciona).

Y eso hizo el truco,  cuando lo ejecute, el WSDL ya estaba correcto:

<wsdl:port name=ServicioSoap binding=tns:ServicioSoap>

<soap:address location=https://empresaX/servicio/funcion.asmx />

</wsdl:port>

Cabe mencionar que esto puede ser util no solo para mi caso, sino para cambiar, por ejemplo, “http” por “https” (el caso de Kirk), o bien, para especificar un puerto diferente para el web service (agregando “:1234″ al final de la direccion).

Y ahi tuve la solucion, despues de apenas 15 horas de trabajar en ella. Espero que si llegas a este post en un caso desesperado, te resulte de utilidad.

Por que el boton de borrar no borra (GridView)

August 27th, 2007

Apenas le estoy agarrando la onda al control DataGridView de .Net Framweork y ahora me estoy peleando con el control GridView de ASP.Net 2.0. Por mucho, me gusta mas la forma en que se maneja esto en windows forms, pero nada es perfecto.

En fin, el punto es que yo ponia bien bonitos mis controles para borrar un registro desde el GridView pero no pasaba nada, el borrado no se hacia. Al final, descubri que hay que especificarle al GridView cual es la llave de nuestra tabla, por medio de la la propiedad DataKeyNames. Hecho esto, el borrado funciona tan bonito como deberia.

Subir archivos via ASP.net facil y rapido

August 24th, 2007

Anteriormente, si se deseaba hacer una  pagina web que tuviera la funcionalidad de subir archivos de la maquina cliente al servidor, usando cosas como el ASP 3, habia que hacer un pequeño circo. Lo mas sensato era buscar alguna DLL de terceros que hiciera el trabajo por ti (como ASP Smart Upload). Y aun si, habia que configurar varias cosas.

Ahora que tuve la necesidad de hacerlo de nuevo, decidi hacer uso de ASP.Net 2.0. Y me encontre con que la tarea se ha facilitado enormemente gracias al contrlo FileUpload.

Basta con poner el control en la pagina que desees, hacer un poco de validaciones y voila! tienes un archivo directo a tu servidor. Unicamente hay que hacer las validaciones necesarias. Pero me parecio increible que con unos cuantos clics pudieras tener esta funcionalidad que antes costara tanto trabajo.

En esta pagina esta la documentacion necesaria para el uso de la clase. Como veran , bastante sencillita.

Un gusano para prevenir ataques de Wordpress

August 2nd, 2007

Leyendo esta entrada en Kriptopolis me entere de algunas nuevas vulnerabilidades descubiertas para la nueva versión de Wordpress, que en efecto, están reportadas en el blog de MyBeni.

Curiosa y afortunadamente, el mismo descubridor de las vulnerabilidades creo un gusano que, mediante XSS, te ayuda a cerrar las mencionadas vulnerabilidades. Es completamente seguro y facil de usar, y también un poco escalofriante, pues te enteras de lo que se puede hacer a través de un ataque de este tipo. Lo recomiendo ampliamente si eres administrador de un blog de wordpress y usas la version 2.2.1

Obtener solo la fecha en una consulta de SQL

July 23rd, 2007

En SQL server, no hay una manera directa de obtener solo la parte de fecha de un campo “DateTime” y no existe unicamente un tipo de campo “Date”. Por lo tanto, si queremos obtener en una consulta, por ejemplo, los registros del dia de hoy, la siguiente consulta no funcionaria:

 select * from tabla where fecha = GetDate()

Esto se debe a que GetDate() nos regresa la fecha y hora en que se ejecuta la consulta, no solo la fecha.

Para hacer posible esta comparacion, podriamos hacer que todas los DateTime se refirieran a las 0:00:00 del dia en cuestion, convirtiendo la fecha a Float y luego usando la funcion Floor de la siguiente manera:

 Cast(Floor(Cast(fecha as Float))as DateTime)

De esta manera, primero convertimos la fecha, y con floor le quitamos todos los minutos y horas “sobrantes”. Despues convertimos de nuevo a DateTime, lo que nos regresara la fecha, con la hora 0. Para poder hacer la comparacion habria que convertir de la misma manera la funcion GetDate().

Como borrar registros duplicados de SQL (the ultimate solution)

July 17th, 2007

El dia de hoy en mi trabajo se me presento un problema con registros duplicados de una tabla de SQL server, asi que me di a la tarea que aqueja a todo DBA alguna vez en su vida. Como borrar registros duplicados de una tabla?  (yo no soy DBA, por cierto, pero aqui hay que hacerla de todo).

En principio de cuentas, una registro duplicado nos habla de un mal diseño, o de base de datos o de procedimientos. En este caso el problema es un error de procedimiento, pero por ahora no hablaremos de eso.

Mi caso esta asi: Tengo una tabla con ID numerico, y un numero x de campos. De esos campos, los registros duplicados son iguales a excepcion de 1 campo (aparte del ID, por supuesto). La tabla tiene algo mas de 4 millones de registros, y habia unos 400,000 duplicados (algunos mas de 6 veces).

Googleando un poco encontre varias soluciones que van desde hacer un Select distinct a una tabla temporal, vaciar la tabla original y luego copiar lo de la temporal a la original (lo cual resulta muy lento), hasta un script que hacia uso de cursores, y que nunca pude hechar a andar.

Todo fue hasta que por ahi me encontre con una solucion simple, rapida y efectiva, que solo requiere que tu tabla contenga un ID numerico. Si no lo tiene, pues lo puedes agregar facilmente, y si despues no lo requieres, puedes borrarlo.

De lo que se trata es de seleccionar la ID mas baja (o mas alta) de cada conjunto de duplicados (tenemos que definir que es un duplicado), y borrar las demas. Simple, no?

Para ejemplificarlo vamos a suponer que tenemos nuestra tabla “Tabla1″.  Esta tabla tiene los campos “ID”, “Campo1″, Campo2″ y “Campo3″. Lo primero que tenemos que hacer es identificar que campos tienen que ser iguales para que un registro sea repetido. Puede ser que sean todos los campos o solo un conjunto de estos. En este ejemplo vamos a decir que Campo2 y 3 son necesarios. Una vez identificados lo que tenemos que hacer es ejecutar la siguiente consulta.

 delete from Tabla1 where Id >
(
Select min(Id) from Tabla1 Tbl1 where Tabla1.Campo2 = Tbl1.Campo2 and Tabla1.Campo3 = Tbl1.Campo3
)

Es todo! Simple, no? Funciona igual si cambias el signo por “<” y  usas “max” en lugar de “min”. En este caso en lugar de conservar el Id mas baja, conservas la mas alta.

Simple y rapido ademas. Mi consulta demoro poco mas de un minuto en buscar y borrar los duplicados en mi tabla de 4 millones. Espero que esta solucion los salve de mas de una. ∞

No se puede ejecutar un ejecutable (sic) desde un DTS

June 29th, 2007

Otro problema con el que me tope el dia de hoy, de esos con soluciones absurdas.

Para los que no conocen los DTS de SQL server, estos son simplemente una forma de agrupar varias tareas y posteriormente ejecutarlas en un solo movimiento. Puedes por ejemplo, traer un archivo de texto, importarlo a una tabla de SQL, y enviar un mail avisando que ya se realizo la tarea. Tiene muchas utilidades practicas.

Muy bien, lo que yo hice en mi DTS fue transformar un archivo de texto en un archivo de Excel, de manera que genero varias hojas de excel y algunas columnas son calculos de otras columnas. Para hacer esto, primero tengo que traer el archivo de texto de algun lado. Asi que lo mas sencillo para mi fue crear un batch que hiciera la tarea de traer este archivo y posteriormente ejecutarlo como la primera tarea de mi DTS.

Todo funcionaba bien en mis pruebas. El problema es que este DTS se manda a ejecutar desde una pagina web, y cuando lo hacia de esta manera, el bat no se ejecutaba.

Mi unica pista era este error en el log del DTS:

Step Error Source: Microsoft Data Transformation Services (DTS) Package
Step Error Description:CreateProcessTask ‘DTSTask_DTSCreateProcessTask_1′:  Process returned code 1, which does not match the specified SuccessReturnCode of 0.
Step Error code: 80040496
Step Error Help File:sqldts80.hlp
Step Error Help Context ID:4900

Despues de escarbar un poco, di con la razon.

Resulta que la tarea de ejecutar archivos del DTS no (siempre) ejecuta el proceso en su ubicacion original, sino que hace una copia del mismo y desde ahi lo ejecuta. Al correrlo desde el Enterprise Manager todo funcionaba bien, pero al ejecutarlo remotamente, lo copiaba a alguna direccion desconocida. Y como mi bat tiene algunas direcciones relativas, pues no trabajaba como era debido.

La solucion: antes de ejecutar la tarea en el bat, tuve que cerciorarme que estuviera trabajando en el directorio correcto.

Esto aplica para cada aplicacion que desees correr desde un DTS, primero asegurate que estas ejecutandola en el sitio indicado. ∞

Server Application Unavailable?¡ Application Pool en IIS

June 29th, 2007

Un buen consejo que me dieron es que usara mi blog para llevar una bitacora de lo que he aprendido, de esta manera no lo olvidare. Asi que he aqui mi historia de un problema que acabo de tener, con su correspondiente solucion.

Hay un servidor aqui en el trabajo con Windows 2003 Server, en el que tengo algunos Web Services y aplicaciones ASP.Net, que hice hace algun tiempo, y que corren bajo el framework 1.1. El dia de ayer me reportaron de que estos servicios habian estado teniendo comportamientos extraños, misteriosamente habian dejado de funcionar.

Normalmente es malo que algo que funciona deje de funcionar sin causa aparente. Asi que me puse a investigar.

Lo primero que intente fue ver si el fallo continuaba, lo cual no resulto asi. Pense que eran de esas cosas extrañas que a veces hacen las computadoras y lo deje en paz.

Sin embargo, al querer revisar una pagina que subi apenas ayer, me tope con este error:

Server Application Unavailable

The web application you are attempting to access on this web server is currently unavailable. Please hit the “Refresh” button in your web browser to retry your request.

Administrator Note: An error message detailing the cause of this specific request failure can be found in the application event log of the web server. Please review this log entry to discover what caused this error to occur.

Fue aqui donde supe que algo malo habia ocurrido.

Lo unico diferente es que esta pagina corre en usando el Framework 2.0. Asi que googleando un poco, descubri mas sobre mi problema y su solucion. Los “application pool”

Resulta que el IIS 6 permite una caracteristica llamada Application Pool. Esta permite aislar los procesos en los que corren nuestras aplicaciones, de manera que si ocurre un error con alguno, no afecta a los demas que no corran en el mismo application pool. Resulta que el IIS permite que varias versiones del framework vivan y se ejecuten felices en el mismo servidor, pero no en el mismo proceso (es decir, en el mismo application pool). La solucion es bien sencilla. Crear un nuevo application pool en el servidor para cada framework.

solucion.JPG

Hecho esto, y poniendo el sitio nuevo a correr en ese application pool, todo se resolvio.

Mas informacion sobre application pool en este sitio. ∞

Va a haber madrazos

April 16th, 2007

Pobrecito de mi blog cero entre cero. Lo tengo todo olvidado. No como su reluciente hermano Doble Negacion, que ya tiene muchos posts y mas trafico. Y parece que en cada post me lamento de lo mismo y prometo que ya ahora si “viene el contenido”.

Supongo que mi parte de desarrollador lleva algo de tiempo dormida, si no del todo al menos bastante adormilada.

Pero bueno, pasemos a la nota. Nota fresquecita por cierto.

En pocas areas de la tecnologia hay poca competencia, normalmente siempre hay muchas y muy buenas opciones para realizar una tarea en especifico. Sin embargo, Adobe (antes macromedia) Flash, se ve como el rey indiscutible del contenido rico en web. Ademas de permitir una creatividad increible tiene una compatibilidad envidiable que le da mucho poder. Le han ido agregando cada vez mas poder para seguir siendo el rey indiscutible de la experiencia rica del usuario…. Hasta ahora.

Resulta que Microsoft acaba de revelar su Microsoft Silverlight. Que promete hacer “lo mismo” que flash… y mas.

Por si mismo Flash es en si un titan. Desconozco hasta ahora las bondades de Silverlight, pero seguro que se va a subir en los hombros de otro titan: el .Net

Como desarrollador adoro mas al .Net entre mas cosas le descubro (apenas ahi la llevo con el 2.0 y ya hay mucho que descubrirle al 3.0). Si se integra el Silverlight al MPF y a toda la plataforma .Net, van a crear un mounstro en lo que a desarrollo de aplicaciones se refiere. Podra Flash, cuyo ActionScript no parece ser tan fuerte, competir con esto? Se va a poner interesante sin duda.

Como comentario al pie, Microsoft podria repetir su conocida formula de tomar la idea de alguien mas y rehacerla un poco, explotandola con su poder y su mercadotecnia, para lograr el exito de su producto, y, en ocasiones, el olvido del original.  ∞