|
Ir a página
|
Siguientes >>
|
|
Lucene para ASP.NET: Un buscador avanzado para tu Web
|
Volver arriba
|
|
Toda aplicación Web que se precie debe tener un buscador. Pero un buscador en condiciones, nada de cosas a medias. Desde Intranets hasta Webs personales, pasando por blogs o redes sociales, el hecho de permitir que el usuario busque contenidos en tu Web es muy recomendable e incluso en algunos casos totalmente imprescindible. En una serie de cuatro artículos en mi blog de Avanzis, analizo la necesidad de un buscador avanzado, introduzco Lucene para .NET y explico cómo indexar documentos y buscar información en ellos:
|
|
Rendimiento en MySql
|
Volver arriba
|
|
Si ya escribo menos de lo que quisiera en este blog, ahora hemos abierto un blog para cada componente de la empresa (Avanzis) y me tengo que repartir (este es mi blog en Avanzis) :D
Pero los artículos más interesantes los iré enlazando aquí.
Hace un par de meses estuve luchando con el rendimiento de MySql en Todoexpertos.com... la lucha me enseñó mucho. Sobretodo me enseñó que yo no tenía ni idea de muchas cosas de MySql y de bases de datos en general 
Pero bueno, no se nace aprendido, y menos sabiendo MySql. En una serie de dos artículos hablo sobre mi aprendizaje:
|
|
Custom Collections
|
Volver arriba
|
Durante los meses en que he estado con GMaps 3.0, he trabajado en mejorar el código de versiones previas. Siempre se puede mejorar en eficiencia, limpieza y mantenibilidad. Durante este artículo os voy a hablar de un Helper que hice con el que se mejorar mucho la mantenibilidad y la limpieza de código. Con las custom collections vamos a poder crear colecciones de "items" o de "nombre-valor" que se convertirán en un string según nuestras necesidades. La necesidad viene de la propia naturaleza del control de googlemaps para ASP.NET, que en su esencia es un "conversor" ASP.NET --> Javascript/API de Google. En muchas ocasiones deberemos devolver colecciones de nombre-valor, donde cada una de ellas es opcional. Por ejemplo, las opciones que se le pasan al contructor de un GMarker pueden ser... {clickable:false,title:'Titulo del GMarker',draggable:true,dragCrossMove:false,bouncy:false,bounceGravity:1} ... o pueden no ser nada. En este caso se trata de una variable JSON, que responde a la definición de "Colección de nombre-valor". Algo también muy común en el javascript de la API de Google Maps que también es una colección de nombre-valor, es una cadena QueryString: ?nombre1=valor1&nombre2=valor2&nombre3=valor3 Por otra parte, tenemos una coleccion de items (o de sólo valor, sin nombre) como por ejemplo los parámetros de un método javascript: (item1, item2, item3) Visto así, no se aporta nada que no pueda solucionarse con un StringBuilder y varios "if", pero creedme que las CustomCollections son brutalmente útiles. Por ejemplo, para crear una variable JSON, sabiendo que todos sus parámetros son opciones, nos vale con el siguiente código: JSONCollection jsonCollection = new JSONCollection(); jsonCollection.Add("clickable", clickable, !clickable, typeof(bool)); jsonCollection.Add("title", title, !string.IsNullOrEmpty(title), typeof(string)); jsonCollection.Add("draggable", draggable, draggable, typeof(bool)); jsonCollection.Add("dragCrossMove", dragCrossMove, draggable, typeof(bool)); jsonCollection.Add("bouncy", bouncy, draggable, typeof(bool)); jsonCollection.Add("bounceGravity", bounceGravity, draggable); string jsonString = jsonCollection.ToString(); El primer parámetro se corresponde al "nombre", el segundo al "valor", el tercero es un booleano que indica si se va a insertar o no en la colección, y el cuarto es el tipo de dato javascript (que no tiene por qué coincidir con el tipo de dato de ASP.NET). Hacer lo mismo con el método tradicional puede ser un infierno de "if-else", StringBuilder y tratamientos diferenciados según si hay o no items que añadir, o si diferenciar si son de tipo booleano, string o entero. Tanto de lo mismo tenmos con la cadena QueryString. Un ejemplo de uso real sería la llamada al servicio Web REST de GeoCoding de Google Maps: QueryStringParameterCollection queryStringParameterCollection = new QueryStringParameterCollection(); queryStringParameterCollection.Add("q", query); queryStringParameterCollection.Add("output", output.ToString()); queryStringParameterCollection.Add("key", Key); queryStringParameterCollection.Add("oe", "ISO-8859-1"); ... string queryString = queryStringParameterCollection.ToString(); Entrando en una faceta más técnica, tanto el JSONCollection, como el QueryStringParameterCollection, como el MethodAttributesCollection, heredan de la clase AdvancedCollection. El AdvancedCollection tiene como propiedades internas un NameValueCollection (para las colecciones nombre-valor) y un StringCollection (para las colecciones de items) a las que se les añadirán elementos con los métodos Add(nombre, valor) y/o Add(item). Las colecciones se transformarán en strings, para lo cual deberemos definir algunos parámetros (pongo entre paréntesis el valor que asignan el JSONCollection, el QueryStringCollection y el MethodAttributesCollection: - StartOfCollection: inicio de la colección. JSONCollection= { QueryStringCollection= ? MethodAttributesCollection= (
- StartOfNameValue: inicio del item o del par nombre-valor. JSONCollection= vacío QueryStringCollection= vacío MethodAttributesCollection= vacío
- NameValuesSeparator: separador de los diferentes nombre-valor y los items. Se distingue de StartOfNameValue y EndOfNameValue, porque el NameValuesSeparator no se inserta tras el último nombre-valor o item. JSONCollection= , QueryStringCollection= & MethodAttributesCollection= ,
- NameValueSeparator: separador entre el nombre y el valor. Cuando sólo tenemos items no tiene efecto. JSONCollection= : QueryStringCollection= = MethodAttributesCollection= Tiene items
- EndOfNameValue: fin del item o del par nombre-valor. JSONCollection= vacío QueryStringCollection= vacío MethodAttributesCollection= vacío
- EndOfCollection: fin de la colección. JSONCollection= } QueryStringCollection= vacío MethodAttributesCollection= )
Así pues, los tres tipos de colecciones son sólo ejemplos ampliables tanto como necesitemos.
|
|
Versión 3.0 del control de Google Maps para ASP.NET
|
Volver arriba
|
Han sido más de dos meses y medio de trabajo en mi tiempo libre, pero por fin ha sido publicada la versión 3.0 del control de Google Maps para ASP.NET.
Esto creo que ya lo he dicho antes, pero puede que se trate del mayor cambio realizado desde que comencé con el control hace ya más de dos años.
Para los que no lo conozcan el control de Google Maps para ASP.NET permite tener un mapa de Google en tu Web. Si quieres algo simple no tienes más que arrastrarlo y ya está. Si quieres algo potente y complejo, no tienes más que programarlo con unas pocas líneas de ASP.NET y ya está :D
Es un control completamente gratuito, aunque dispone de licencias (muy baratas) si lo vais a utilizar a nivel comercial.
La web del control (googlemaps.subgurim.net) trae una sección "Cómo..." a modo de tutorial, una galería de código con ejemplos más específicos, y una galería de iconos.
Para conocer los cambios, lo mejor es que le echéis un vistazo al changelog.
|
|
UpdatePanel.IsInPartialRendering, ¿funciona?
|
Volver arriba
|
He estado trabajando con el IsInPartialRendering del UpdatePanel y me he dado cuenta que NO FUNCIONABA... ¿cómo es eso posible?
He estado buscando, y todo lo que he visto eran quejas por este (aparentemente) tremendo bug. De hecho he visto piezas de código similares a obras de arte capaces de encontrar con un montón de recursividades e historias si nuestro UpdatePanel estaba en un PartialRendering.
Esas piezas de código funcionan bien, pero el problema de base es el que solemos cometer muchos programadores. Cuando algo no funciona, lo asignamos enseguida a bugs de terceros, en los que nada podemos hacer, y nos quedamos tan panchos.
Pues NO, esa es una práctica que debemos desestimar. Ese tipo de bugs es demasiado evidente para perdurar tanto tiempo, con lo que inmediatamente debemos pensar que algo estamos haciendo mal.
Y así es, porque el IsInPartialRendering funciona perfectamente bien. El único problema es no saber utilizarlo. Porque sólo nos da la información buena a partir de las últimas fases del ciclo de vida. Específicamente funciona a partir del "Render", algo, por otra parte, bastante lógico.
Así que ya sabéis, si en algún momento necesitáis saber si cierto UpdatePanel está en PartialRendering, debéis manejar el evento OnRender.
|
|
Diccionario javascript que se puede leer en ASP.NET
|
Volver arriba
|
Ahora mismo estoy al 100% en la nueva versión de mi control de Google Maps para ASP.NET (la 3.0). Estoy tardando más de lo que tenía pensado (prueba de ello es el "abandono" que tiene este blog), pero es que la cantidad de mejoras es enorme.
Una de las pequeñas cositas que voy a añadir es un diccionario para javascript que puede leerse en ASP.NET. Es una pequeña "clase" javascript que me ha quedado muy chula y aunque en el control de GoogleMaps no se hace trabajo directo con ella, pues es una librería auxiliar, la comparto con vosotros porque puede llegar a ser útil.
El objetivo es que desde javascript podamos crear un sencillo diccionario con su Clave-Valor y su Get-Set, y que al hacer un PostBack tengamos acceso a éste.
Lo único que vamos a necesitar es un input-type-hidden en nuestra página. Por ejemplo:
<input type="hidden" id="subgurim_Store" name="subgurim_Store" />
Aprovecho para recordar que los input-type-hidden deben tener el atributo "name", si no, desde ASP.NET no se podrá leer con el Request.Form.
Antes de enseñaros la libreria, aquí hay un ejemplo de uso.
Javascript var myStore = new Store('subgurim_Store'); myStore.Set('key1', 'value1'); myStore.Set('key2', 'value2'); myStore.Set('key3', 'value3');
alert(myStore.Get('key2')); myStore.SaveHidden();
ASP.NET protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) string subgurim = Request.Form.Get("subgurim_Store"); }
De modo que el string subgurim tendrá el valor "key1=value1&key2=value2&key3=value3". A partir de ahí es muy sencillo obtener cada Key-Value. En mi control de GoogleMaps tengo una librería que lo hace sólo, pero eso queda para otro artículo :D
Así que os enseño la sencilla librería. La he testeado poquito, y seguro que es mejorable, pero por lo menos sabemos que por ahí van los tiros. Por cierto, hay algunas cosillas que pueden parecer innecesarias (por ejemplo que algunas funciones sean públicas cuando podrían ser privadas, pero es que está adaptado a mi control de GoogleMaps y ahí sí me hace falta.
// le pasamos el identificador del input-type-hidden function Store(id) { if (!id) return; this.id = id;
// En la variable "s" es donde está la magia. Aquí se guarda todo. this.s = {}; // Referenciamos el objeto hidden para poder usarlo en cualquier lado. // Faltaría comprobar que realmente existe, etc. this.hidden = document.getElementById(this.id); // Al inicializar la variable queremos rellenar this.s con lo que ya tiene el hidden // De esa forma, aunque hagamos PostBacks, nuestro this.s será persistente this.FillFromHidden();
// Cuando rellenamos this.s queremos borrar el hidden, obligándonos a evitar // desincronizaciones innecesarias. this.hidden.value = ''; } Store.prototype.Get = function(key) { return this.s[key]; } ; Store.prototype.Set = function (key, value) { this.s[key] = value; } ; // Recoge los valores de this.s y los guarda en el hidden. // Hay que llamar a este método siempre que terminemos de trabajar con el objeto Store. Store.prototype.SaveHidden = function () { var hiddenValue = ''; for (key in this.s) { var value = this.s[key]; if (key && value) hiddenValue += key + '=' + value + '&'; } hiddenValue = hiddenValue.substring(0, hiddenValue.length - 1); this.hidden.value = hiddenValue; } ; // Recoge el valor del Hidden y lo mete en this.s Store.prototype.FillFromHidden = function () { var hiddenValue = this.hidden.value; var keyValueArray = hiddenValue.split('&'); for (var i=0; i<keyValueArray.length; i++) { var keyValue = keyValueArray[i].split('='); var key = keyValue[0]; var value = keyValue[1]; this.s[key] = value; } } ;
|
|
Hacer un RadioButton dentro de un Repeater
|
Volver arriba
|
Estos últimos días me he estado peleando con una cosilla algo rara en Todoexpertos. Y es que a veces ASP.NET tiene algunas cosas que te dan ganas de tirarte de los pelos... o tirarle de los pelos a ScottGu (aunque no tenga muchos).
Mi objetivo era bien sencillo. En lugar de utilizar un control RadioButtonList, lo que yo quería era generar diferentes RadioButtons usando el control Repeater, de modo que cuando seleccionas en cualquier RadioButton, el que estaba seleccionado previamente (si lo había) se deseleccionase, y sólo quedara uno.
Esto es algo bastante típico y muy sencillo de llevar a cabo, sin más que ponerle a todos los RadioButton el mismo "GroupName", que se acaba convirtiendo en el atributo "name" en HTML.
Pero ahora viene el problema, y es que al estar dentro de un Repeater, ASP.NET va generando un prefijo único al name (al igual que hace con el ID), de modo que no es posible que todos tengan el mismo name, por mucho GroupName que especifiques.
Tan sencillo como lo quería, tan sencillo como ASP.NET hacía la puñeta.
Pero bueno, menos mal que javascript y yo somos bastante amigos y pronto Googleé una solución que no tuve más que modificar a mi gusto.
La función javascript que utilicé es el siguiente:
function SetUniqueRadioButton(nameregex, rid) { re = new RegExp(nameregex); rb = document.getElementById(rid); var inputs = document.getElementsByTagName('input'); for(i = 0; i < inputs.length; i++) { elm = inputs[i] if (elm.type == 'radio') { if (re.test(elm.name)) { elm.checked = false; } } } rb.checked = true; }
Y al radiobutton hay que ponerle esto dentro de su atributo "onclick":
onclick="SetUniqueRadioButton('Repeater1.*', '" + RadioButton1.ClientID + "')"
Como vemos, por una parte le estamos pasando una expresión regular, y por otra el Identificador que Javascript sabrá leer.
Lo que hace la función javascript es leer todos los elementos "input" de la página, se asegura de que sean de type "radio" y, de ser así, que cumplan la expresión regular. Siempre se le pone el checked=false, para, posteriormente, poner el checked=true a nuestro RadioButton.
Ya sé la pregunta... ¿qué narices representa la expresión regular? Lo único que representa es el prefijo que el simpático de ASP.NET le va a poner a todo elemento que esté dentro del Repeater1. No tenéis más que poner el identificador del Repeater y ya está 
Espero que os sea útil.
|
|
iWhere: aplicación para Facebook
|
Volver arriba
|
Durante estas semanitas he estado trabajando en mis ratos libres en una aplicación muy chula para Facebook.
Bueno, lo de chula lo digo yo, jeje.
En realidad no se trata de una aplicación para Facebook sólo, sino que mi intención era usar "TodasLasCosasNuevas" que se me ocurrían, como todo tipo de mejoras de ASP.NET 3.5: expresiones lambda, el uso de "var", inicializadores, LINQ para SQL, y demás cosillas que han dejado una respetable cosecha de potenciales artículos para este blog.
En cuanto a programar para Facebook, he usado el Facebook Developer Toolkit, en detrimento del Facebook.NET. Prácticamente ambos hacen lo mismo, y por lo único por lo que me he decidido por el primero es porque tenían más descargas, más visitas y más actualizaciones (aunque eso no significa apenas nada).
Lo único que tengo claro es que programar aplicaciones para Facebook usando el Toolkit es absolutamente sencillo. Apenas un par de cambios con respecto a programar en ASP.NET y ya está.
En cuanto a la aplicación en sí, se trata de dar a conocer a tus amigos de dónde eres, sin más que elegir un punto en el mapa. Cuando has indicado de dónde eres, puedes ver de dónde son tus amigos en un mapa... obviamente un mapa de Google, y así he aprovechado para utilizar mi propio control de GoogleMaps para ASP.NET porque desde ya mismo comienzo con una nueva versión (por cierto, todavía estoy dudando en si sacar una pequeña nueva versión 2.8 o hacer un gran cambio con la versión 3.0).
Por cierto... no he dicho la url de la aplicación, ¿no? Podéis accederla desde http://apps.facebook.com/iwheere/
Sí, tiene repetida la letra "e" porque Facebook requiere que la url de sus aplicaciones tenga más de 6 letras. Además es case sensitive... manda narices... en PHP tenía que estar hecho el Facebook ese, jaja.
Si queréis me podéis añadir como amigo (buscad a Subgurim) 
|
|
Ir a página
|
Siguientes >>
|
|
|