Este post viene a modificar el ejemplo anterior, es uno en donde ocupamos elementos HTML5 y Modernizr para cargar distintos polyfills para solucionar el problema de la compatibilidad.
Ahora, para darle un poco más “choreza” como decimos por acá, vamos agregar audio con HTML5. Ahora bien, no creo que mucha gente le interese escuchar el sonido a cada rato, pero bueno, es para fines demostrativos.
La modificación al ejemplo consistirá en dejar el formulario oculto y crear una especia de acordeón, de tal manera de ejecutar un sonido cuando se abra y cierre el acordeón.
Algo así:
 |
 |
|
Estado Cerrado (inicial)
|
Estado Abierto
|
En cada abrir y cerrar reproduciremos un sonido, el resultado es el del siguiente video:
Entonces manos a la obra, primero vamos a agregar los tags de audio
<audio id="abrir" preload="auto">
<source src="audio/abrir.mp3" type="audio/mpeg" />
<source src="audio/abrir.ogg" type="audio/ogg" />
</audio>
<audio id="cerrar" preload="auto">
<source src="audio/cerrar.ogg" type="audio/ogg" />
<source src="audio/cerrar.mp3" type="audio/mpeg" />
</audio>
Como vemos no es necesario mostrar los controles del tag audio, luego, mediante jQuery vamos a hacer play a esto controles.
Los archivos de audio mp3 y ogg los convertí desde wav mediante esta herramienta gratuita (cuidado con sus barras para IE instalables)http://www.koyotesoft.com/audio-software/free-mp3-wma-converter.html imagino que hay mucho mejores, pero fue lo primero que encontré. Entonces, en la carpeta audio agregamos los archivos y listo!

PD: Recuerda que no todos los navegadores soportan los mismos codec para reproducción de audio y video, por eso tenemos que agregar diferentes formatos para asegurar compatibilidad. Puedes ver el siguiente cuadro para tener el escenario con el que vas a tener que lidiar:

Ahora el código jQuery, muy simple para crear el efecto y puedes notar el atributo play para el tag audio con id abrir y el otro tag con el id cerrar:
$(document).ready(function(){
$("form").hide();
$("#texto").toggle(function(){
$("form").slideDown("slow");
$("#texto").html("- Cerrar");
$("#abrir")[0].play();
},function(){
$("form").slideUp("slow");
$("#texto").html("+ Abrir");
$("#cerrar")[0].play();
});
});
Y estamos ok, ya tenemos nuestro ejemplo balls breaker con sonido 
Espero que te sirva!
@chalalo
Hola que tal, este vez revisaremos tres ejemplos prácticos en donde podemos utilizar modernizer para detectar características del browser y decidir según la disponibilidad de ellas que hacer, como por ejemplo, incluir librerías o polyfills para mitigar el problema. Puedes ver mi articulo anterior en donde iniciamos esta serie de ejemplos prácticos.
Vamos dos problemáticas , la de la archi nombrada característica de HTML5 de bordes redondeados,también el nuevo elemento date formulario y por ultimo la propiedad “required” de los elementos del formulario.
Ejemplo:
Veamos que cuenta con las siguientes características HTML5:
- Bordes Redondeados
- Campo Date en el formulario
- Campo Date es obligatorio
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Demo</title>
<style type="text/css">
form{
background-color:#9fbfa3;
width:300px;
padding:15px;
border-radius:10px;
}
</style>
</head>
<body>
<form id="formulario" action="#">
<label for="TxFecha">Seleccione Fecha</label>
<input type="date" name="TxFecha" id="TxFecha" required>
<input type="submit" id="btEnviar" value="Enviar">
</form>
</body>
</html>
El resultado en un IE9 es:

Si bien existen el soporte a bordes redondeados, no se soporta el campo email ni el atributo “required”
IE7 (Probando con IE9 En modo explorador IE7), no existe soporte para ninguna funcionalidad.

En Chrome (16.0.912.77 m), si bien se soporta además el atributo required, no se soporta el campo date:

Veamos ahora en Firefox 9.0.1, al igual que Chrome, no se soporta el campo date.

El turno de Safari, no soporta required y si bien soporta el campo fecha, lo hace de una manera deficiente a mi parecer, pero al fin y al cabo, lo soporta.

Opera, al menos para nuestro ejemplo, lleva la delantera soportando todas las funcionalidades.

Ahora vemos como arreglar el código para que exista soporte para bordes redondeados para todos los navegadores:
Primero vamos a ver como solucionar el tema del Borde Redondeado.
Los pasos a seguir serán:
- Agregar librería Modernizr y jQuery (estoy utilizando versiones de desarrollo)
- Agregar, solo para asegurarnos de compatibilidad hacia atrás, las propiedades CSS para border radius propietarias.
- Agregar y ejecutar la librería jquery.corner en el caso de que el browser no soporte nativamente la característica de bordes redondeados, de manera que este script proporcione la funcionalidad, notar que es lazy download, es decir solo se va cargar esta librería cuando se necesite.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Demo</title>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.0.6-development-only.js"></script>
<style type="text/css">
form{
background-color:#9fbfa3;
width:300px;
padding:15px;
-moz-border-radius: 10px;
-webkit-border-radius:10px;
border-radius: 10px;
}
</style>
</head>
<body>
<form id="formulario" action="#">
<label for="TxFecha">Seleccione Fecha</label>
<input type="date" name="TxFecha" id="TxFecha" required="true">
<input type="submit" id="btEnviar" value="Enviar">
</form>
</body>
</html>
<script type="text/javascript">
if (!Modernizr.borderradius) {
$.getScript("js/jquery.corner.js", function () {
$("form").corner();
});
}
</script>
Si ejecutamos esta página en IE7 veremos:

Es decir, ya no hay problema de los bordes redondeados, ahora continuemos con el calendario, para esto vamos a utilizar JqueryUI, el script de calendario, para ello seguiremos los siguientes pasos:
- Determinar si el navegador soporta el tag input type=”date” mediante modernizer
- En caso que el browser no cuente con esta característica, cargar el script de jQueryUI y asignárselo al campo fecha, además de cargar dinámicamente el CSS asociado.
if (!Modernizr.inputtypes.date) {
$.getScript("http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.17/jquery-ui.min.js",
function () {
var css = jQuery("<link>");
css.attr({ rel: "stylesheet",
type: "text/css",
href: "http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.17/themes/ui-lightness/jquery-ui.css"
});
$("head").append(css);
$("#TxFecha").datepicker();
});
}
Ahora ejecutamos en IE y veremos

Tenemos bordes redondeados y calendario, pero falta el validador, esta vez no usé jQuery-Validator, ya que lo consideré mucho para un solo campo, pero obviamente consideraría JV para la próxima, en este caso, yo mismo hice una validación de requerido, obviamente es solo a modo de ejemplo, le queda mucho ser algo para producción.
if (!Modernizr.input.required){
$("#formulario").submit(function(){
if ($("#TxFecha").val().length==0){
return fallo();
}else{
return normal();
}
});
$("#TxFecha").focus(normal);
}
function normal(){
$("#TxFecha").css("background","white");
$("#TxFecha").css("color","black");
$("#TxFecha").val("");
return true;
}
function fallo(){
$("#TxFecha").css("background","red");
$("#TxFecha").css("color","white");
$("#TxFecha").val("Este campo es necesario");
return false;
}
Luego al probarlo, tenemos lo siguiente:

Si bien no es lo mismo, podemos lograr un efecto más deseado con distintos plugins.
Para terminar veamos las cargas de archivos con los dos navegadores (obviamente todos van a cargar jQuery y Modernizr)
IE7 (todos los polyfills)

IE9(Solo jQueryUI, ya que soporta bordes redondeados)

Firefox(Solo jQueryUI, ya que soporta bordes redondeados)

Chrome(Solo jQueryUI, ya que soporta bordes redondeados)

Opera (No necesita cargar pollyfills)

Como puedes ver, solo se cargan los scripts cuando se les necesita, aumentando el rendimiento.
Espero que les sirva!
Saludos,
Hola, en esta ocasión quiero volver a tocar el tema de la ejecución en paralelo de métodos en ASP.NET, que si bien está muy optimizado en la versión 4.5, que aún está en desarrollo, muchos de nosotros no tenemos planes a corto plazo de migrar para aprovechar las ventajas.
Veamos un escenario común, grillas grillas combos combos, a que me refiero con esto, es que muchas veces nuestros sistemas cargan una cantidad considerable de combos que no están asociados e igual cantidad de grillas en el Page Load. Generalmente no es necesario que esto se cargue secuencialmente, y podemos aprovechar las ventajas en términos de tiempo al utilizar la carga en paralelo.
Para explicar un poco más vamos a crear un pequeño proyecto, que tenga 2 DropDownList (o combos, como le llamamos universalmente). Cada uno de estos combos va a tener una duración de carga de 3 segundos, obviamente de manera secuencial se va a demorar mínimo 6 segundos la carga de la página, mientras que en paralelo, claro como el agua, mínimo 3 segundos:
Ahora veamos el código
El código de la página con carga secuencial:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
dd_ciudades.DataSource = Obtciudades()
dd_ciudades.DataBind()
dd_regiones.DataSource = Obtregiones()
dd_regiones.DataBind()
End If
End Sub
Public Function Obtciudades() As List(Of Ciudad)
System.Threading.Thread.Sleep(3000)
Dim ciudades As New List(Of Ciudad)
ciudades.Add(New Ciudad With {.id = 1, .nombre = "Concepcion"})
ciudades.Add(New Ciudad With {.id = 2, .nombre = "Santiago"})
ciudades.Add(New Ciudad With {.id = 3, .nombre = "Viña del Mar"})
ciudades.Add(New Ciudad With {.id = 4, .nombre = "Puerto Montt"})
ciudades.Add(New Ciudad With {.id = 5, .nombre = "Cañete"})
Return ciudades
End Function
Public Function Obtregiones() As List(Of Region)
System.Threading.Thread.Sleep(3000)
Dim regiones As New List(Of Region)
regiones.Add(New Region With {.id = 1, .nombre = "Primera Region"})
regiones.Add(New Region With {.id = 2, .nombre = "Segunda Region"})
regiones.Add(New Region With {.id = 3, .nombre = "Tercera Region"})
regiones.Add(New Region With {.id = 4, .nombre = "Cuarta Region"})
regiones.Add(New Region With {.id = 5, .nombre = "Quinta Region"})
Return regiones
End Function
Puedes notar los métodos Sleep para causar la demora en el thread de ejecución en cada uno de los métodos que sirvan para poblar los dropdownlist.Ahora si vemos la carga del la página con el IE Developer Toolbar, el resultado son 6.07 segundos:

Veamos el código para ASP.NET 3.5, es más largo pero la relación costo beneficio es muy buena, ya que vamos a bajar los tiempos casi a la mitad. Como dije anteriormente, implementar esta misma funcionalidad en ASP.NET 4.5 es mucho más sencillo, ya que elimina las complejidades al momento de especificar cuales métodos serán ejecutados de manera Asíncrona, pero eso lo dejaremos para otro post 
Imports Microsoft.VisualBasic
Imports System.Threading
Partial Class Paralelo
Inherits System.Web.UI.Page
Private ehRecuperarDatosDeDropDownList1 As EventHandler = Nothing
Private ehRecuperarDatosDeDropDownList2 As EventHandler = Nothing
Private listaRegiones As New List(Of Region)
Private listaCiudades As New List(Of Ciudad)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim pat1 As New PageAsyncTask(New BeginEventHandler(AddressOf
Me.RecuperarDatosDeDropDownList1), New EndEventHandler(AddressOf
Me.CargarDropDownList1), Nothing, Nothing, True)
Dim pat2 As New PageAsyncTask(New BeginEventHandler(AddressOf
Me.RecuperarDatosDeDropDownList2), New EndEventHandler(AddressOf
Me.CargarDropDownList2), Nothing, Nothing, True)
Page.RegisterAsyncTask(pat1)
Page.RegisterAsyncTask(pat2)
End Sub
#Region "dd_regiones"
Private Function RecuperarDatosDeDropDownList1(sender As Object, e As
EventArgs, cb As AsyncCallback, state As Object) As IAsyncResult
Me.ehRecuperarDatosDeDropDownList1 = New EventHandler(AddressOf
Me.RecuperarRegiones)
Return Me.ehRecuperarDatosDeDropDownList1.BeginInvoke(Me,
EventArgs.Empty, cb, Nothing)
End Function
Private Sub RecuperarRegiones(sender As Object, e As EventArgs)
Me.listaRegiones = Obtregiones()
End Sub
Private Sub CargarDropDownList1(ar As IAsyncResult)
Me.ehRecuperarDatosDeDropDownList1.EndInvoke(ar)
Me.dd_regiones.DataSource = Me.listaRegiones
Me.dd_regiones.DataBind()
End Sub
Public Function Obtregiones() As List(Of Region)
System.Threading.Thread.Sleep(3000)
Dim regiones As New List(Of Region)
regiones.Add(New Region With {.id = 1, .nombre = "Primera Region"})
regiones.Add(New Region With {.id = 2, .nombre = "Segunda Region"})
regiones.Add(New Region With {.id = 3, .nombre = "Tercera Region"})
regiones.Add(New Region With {.id = 4, .nombre = "Cuarta Region"})
regiones.Add(New Region With {.id = 5, .nombre = "Quinta Region"})
Return regiones
End Function
#End Region
#Region "dd_ciudades"
Private Function RecuperarDatosDeDropDownList2(sender As Object, e As EventArgs, cb As AsyncCallback, state As Object) As IAsyncResult
Me.ehRecuperarDatosDeDropDownList2 = New EventHandler(AddressOf Me.RecuperarCiudades)
Return Me.ehRecuperarDatosDeDropDownList2.BeginInvoke(Me,
EventArgs.Empty, cb, Nothing)
End Function
Private Sub RecuperarCiudades(sender As Object, e As EventArgs)
Me.listaCiudades = Obtciudades()
End Sub
Private Sub CargarDropDownList2(ar As IAsyncResult)
Me.ehRecuperarDatosDeDropDownList2.EndInvoke(ar)
Me.dd_ciudades.DataSource = Me.listaCiudades
Me.dd_ciudades.DataBind()
End Sub
Public Function Obtciudades() As List(Of Ciudad)
System.Threading.Thread.Sleep(3000)
Dim ciudades As New List(Of Ciudad)
ciudades.Add(New Ciudad With {.id = 1, .nombre = "Concepcion"})
ciudades.Add(New Ciudad With {.id = 2, .nombre = "Santiago"})
ciudades.Add(New Ciudad With {.id = 3, .nombre = "Viña del Mar"})
ciudades.Add(New Ciudad With {.id = 4, .nombre = "Puerto Montt"})
ciudades.Add(New Ciudad With {.id = 5, .nombre = "Cañete"})
Return ciudades
End Function
#End Region
End Class
Ciertamente el código puede resultar confuso,(adjunto el código fuente, ya que se ve mejor en Visual Studio que en el blog), primero se registran las “tareas” que vamos a correr en paralelo, cada tarea tiene un método de inicio(BeginEventHandler), y método de finalización (EndEventHandler), luego registramos cada una de estas tareas, en este caso son dos, lo hacemos llamando al método RegisterAsyncTask de la página.
Los métodos ObtCiudades y ObtieneRegiones no sufren alteraciones, ahora al momento de ejecutar la página, obtenemos mejores tiempo, tal cual habíamos estimado, 3,16 segundos.

Claro está que solo estoy usando esta funcionalidad con dos métodos, puedes utilizarlos con más según tu conveniencia.
Puedes bajar el código desde acá

Espero que te sirva!
@chalalo

Como ya saben Modernizr es una librería JavaScript que nos permite detectar las capacidades del soportadas por el navegador en relación a HTML5 y CSS3. Esto nos será en extremo útil cuando estemos desarrollando nuestras páginas con funcionalidades incluidas HTML5 y deseemos que, en la medida de lo posible, usuarios con navegadores antiguos puedan tener la misma experiencia de usuarios, es decir, simular la característica nativa de HTML5 con un pollyfill, que básicamente son códigos o plugins que proveen la tecnología que nosotros, los desarrolladores, esperaríamos que el browser soportara nativamente.
Ejemplo práctico – PlaceHolder
El atributo Placeholder
Atributo HTML5, que podemos describirlo como el texto que aparece dentro de un campo de texto antes de que este tenga el foco, cuando el campo pierde el foco y si el campo está vacío, aparece nuevamente el texto. Ejemplo:
<label for="Rut">Ingrese su Rut:</label>
<input type="text" placeholder ="Ej: 13657654-K" id="rut" />
Lo que resulta en lo siguiente:

Ahora bien, que pasa y con browser que no soporten esta característica? y como detectamos si el browser que navega nuestra página no soporta esta funcionalidad? Tenemos dos opciones:
La más fácil : No hacer nada, simplemente las personas que naveguen con browser antiguos no van a tener esta funcionalidad
Lo mejor, mantener la experiencia de usuario, utilizando Modernizer y PollyFills
Paso 1, Agregar la librería Modernizr
<script src="js/modernizr-1.5.min.js"></script>¨
Paso 2, Agregar el código de detección y Pollyfill
if(!Modernizr.input.placeholder){
$('[placeholder]').focus(function() {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
input.removeClass('placeholder');
}
}).blur(function() {
var input = $(this);
if (input.val() == '' || input.val() == input.attr('placeholder')) {
input.addClass('placeholder');
input.val(input.attr('placeholder'));
}
}).blur();
$('[placeholder]').parents('form').submit(function() {
$(this).find('[placeholder]').each(function() {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
}
})
});
Como puedes ver, el primer if , detecta mediante el objeto Modernizr la capacidad del navegador , y si no soporta placeholder (que es un atributo de input), entonces aplicamos el código jQuery que provee la misma funcionalidad del placeholder nativo HTML5.

En navegadores que aún no soportan este atributo, mediante la técnica de graceful degradation vamos a lograr similares experiencias de usuario en navegadores antiguos.
Saludos!, pronto subo más ejemplos.
@chalalo
Hola!, para empezar el año, les dejo un video de algunas de las nuevas características de Visual Studio 2011 para el desarrollo con ASP.NET. Bueno ya estamos en el 2012, quizás Visual Studio cambie de nombre a Visual Studio 2012, no lo sé. Sin más teorías, acá está el video:
Los puntos a tratados en este WebCast son:
- Nuevas características en el Solution Explorer
- Nuevas características de desacoplamiento de ventanas
- Editor CSS (Regiones, Helpers, Autocompletación)
- Editor JavaScript (Referencia de Definiciones, Referencia a librerías)
- Nuevas posibilidades del editor de código (Asociar Eventos, agregar columnas en grillas)
- Repeters Tipados, Bundling , Validaciones no Intrusivas
- Instalación de Librerías mediante NuGet , ValidateRequestMode.
Espero que les sea de ayuda 
Saludos!
@chalalo
Hola, les dejo el video del Webcast que di sobre MongoDB y ASP.NET. No profundicé mucho pero creo que la se entiende, en este mismo blog están los códigos que se mostraron en la presentación, cualquier duda, no dudes en consultar.
Saludos!
@chalalo.
Hola, les dejo la grabación del WebCast que realizé el día martes 20 de Diciembre, está basada en la charla del mix2011 Master Rey Bango, con algunos aportes propios.
Véanla en HD, mucho mejor! :)
Saludos!
@Chalalo
Holas, ya es fin de año pero no por eso se bajan las revoluciones!. Te invito a una serie de WebCast que voy a impartir:
Webcast MSDN:Cómo llenar los vacíos de HTML5 con Pollyfills y Shims
 |
Todo el mundo quiere saltar a HTML5, pero ¿cómo usar las mejores características de esta nueva especificación garantizando al mismo tiempo que los navegadores más antiguos ofrece páginas Web como se esperaba? Aquí es donde entran los multillenados y las cuñas. En la sesión, aprenderás cómo usar el código especialmente diseñado para JavaScript y CSS que emula las características de HTML5 para que puedas tomar ventaja de HTML5 hoy sin romper tus sitios en navegadores antiguos.
|
Fecha – Hora:
martes 20 de diciembre de 2011 - 06:00PM (Chile)
martes 20 de diciembre de 2011 - 4:00PM (Bogotá)
Registrarse aquí
----------------------------------------------------------------------------------------------------------
Webcast MSDN: Desarrollo de Aplicaciones Web con ASP.NET y MongoDB
 |
MongoDB es una base de datos multiplataforma orientado a documentos, OpenSource preparada para alta disponibilidad y High-Performance, que es una de las principales exponentes del movimiento NoSQL.
|
En esta sesión veremos una introducción a esta nueva filosofía en el manejo de datos y como utilizarla para nuestros proyectos ASP.NET MVC y ASP.NET WebForms
Fecha – Hora:
viernes 23 de diciembre de 2011 - 03:00PM (Chile)
viernes 23 de diciembre de 2011 - 01:00PM (Bogotá)
Registrarse aquí
----------------------------------------------------------------------------------------------------------
Webcast MSDN: Una visión general de MS Web Stack of Love
 |
La creación de aplicaciones Web en la pila de Microsoft continúa evolucionando. Hay un montón de grandes herramientas que se pueden aprovechar, pero puede ser difícil mantenerse al día con todas las opciones disponibles. |
En esta sesión técnica y con un ritmo rápido, aprenderás cómo encajan las piezas. Nos ocuparemos de ASP.NET MVC 3, MvcScaffolding, Entity Framework Code First (Magic Unicorn Edition), SQL Compact 4, jQuery y mucho más.
Fecha – Hora:
martes 27 de diciembre de 2011- 12:00PM (Chile)
martes 27 de diciembre de 2011- 10:00AM(Bogotá)
Registrarse aquí
Hola , acabo de publicar un ScreenCast sobre Geolocalizacón de HTML5, lo puedes ver este y otros ScreenCasts en :
Pero bueno, si quieres verlo por acá , comporto también el Video:
Descarga los archivos utilizados en el Screencast
Saludos!
@chalalo

Hola, si recueras mi post anterior sobre MongoDB y ASP.NET MVC, vimos como instalar mongoDB, instalar las librerías y utilizarlo junto a ASP.NET MVC. Esta vez veremos como utilizar ASP.NET Webforms con VB.NET junto a MongoDB para crear búsquedas de texto.
El problema
Tenemos aproximadamente 105.000 registros, que corresponden a un listado de diagnósticos posibles. Las búsquedas de texto siempre (o al menos la mayoría de las veces) son bastante costosas en términos de procesamiento, entonces para liberar la carga de nuestro ya exigido motor de BD, decidí utilizar mongoDB para estas búsquedas.
Los registros para la búsqueda tienen un código que se puede repetir y una descripción del diagnóstico, ej:
A244;Infeccion por Pseudomonas pseudomallei
A244;Melioidosis
A244;Neumoenteritis
A244;Neumonia debida a Pseudomonas pseudomallei
A250;Espirilosis
A250;Fiebre espirilar
A250;Fiebre mordedura debida Spirillum
No tengo idea que significan esos diagnósticos (y no me las doy de House MD). Entonces la idea e poder buscar por palabras, por ejemplo “mordedura” y “Spirillum” y obtener el o los registros concordante con los parámetros de búsqueda.
La Solución
Este post es parte de la solución, para eso armé un prototipo(que es el que ves en la siguiente imagen, un webform asp.net con vb.net)
La estructura, (si, Webform)

Diseño (si es que se puede llamar diseño)

Los botones AJ y KZ cargan los datos de lo archivos hacia mongoDB, y luego la búsqueda , consulta esos registros por las palabras ingresadas y lo muestra en el textarea.
Leyendo la documentación, revisé que se recomendaba crear un objeto con Keywords de búsqueda, es decir, las palabras relevantes, en mi caso todas las palabras que tengan más de 2 letras en la palabra. Veamos cual es la clase que utilizé: (Tapsa se llama el concepto de lista de diagnósticos)
Class Tapsa
<BsonId()> _
Public Id As ObjectId
Public codigo As String
Public texto As String
Public _keywords As List(Of String)
End Class
Como ves, la _keywords es una lista de String, así que para cargar la lista de registros desde el archivo, voy a utilizar la siguiente función asociada a un botón(por el ejemplo), eliminando las palabras con menos de 3 letras.
Pero primero, la conexión a MongoDB
Private Function DB() As MongoDatabase
Dim server = MongoServer.Create("mongodb://localhost")
Dim dbm As MongoDatabase = server.GetDatabase("sinetsur")
Return dbm
End Function
Lueego el botón AJ, que hace lo mismo que el botón KZ, solo cambia el archivo:
Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
Dim sr As New StreamReader(Server.MapPath("ajC.csv"))
Dim linea As String = sr.ReadLine()
Dim tapsaas As MongoCollection(Of tapsa) = DB.GetCollection(Of tapsa)("tapsaas")
Do While linea <> Nothing
Dim tp As New Tapsa() With {.codigo = linea.Split(";")(0), .texto =
linea.Split(";")(1), ._keywords = divide(linea.Split(";")(1))}
tapsaas.Insert(tp)
linea = sr.ReadLine()
Loop
sr.Close()
End Sub
Y la función Divide, que devuelve un la lista de String, ignorando las palabras “cortas”
Private Function divide(texto As String) As List(Of String)
Dim lista As New List(Of String)
For Each obj In texto.Split(" ").ToList
If obj.Length > 2 Then
lista.Add(obj.ToLower)
End If
Next
Return lista
End Function
Con esto ya llené mi colección MongoDB, veamos como se visualiza la colección:

O si lo prefieres ver en formato JSON:
{
"_id" : ObjectId("4edf74d4ac7d9820405ca343"),
"codigo" : "A021",
"texto" : "Septicemia debida a Salmonella cholerae-suis",
"_keywords" : ["septicemia", "debida", "salmonella", "cholerae-suis"]
}
Puedes ver que existen 4 keywords y el texto era de 5 palabras, pero el “a” es totalmente ignorable.
Puedes probar en el Shell de MongoDB las búsquedas, por ejemplo escribimos lo siguiente en la consola:
db.tapsaas.find({"_keywords": { "$all": ["dolor","ojo"] }});
El resultado fue prácticamente inmediato, pero aún se puede ejecutar la consulta más rápido, esto es creando un índice por el campo keywords
db.tapsaas.ensureIndex({_keywords:1});
El proceso de creación del índice varia dependiendo de el campo al que se le aplica y a la cantidad de registros que ya existen en dicha colección. y bueno con esto creamos el índice, y ahora las búsquedas simplemente vuelan. (luego me referiré en detalle sobre el profiler de MongoDB, en otro post)
Ahora vamos revisar el código de la búsqueda (botón Búsqueda).
Protected Sub Button2_Click(sender As Object, e As System.EventArgs) Handles Button2.Click
tx_resultado.Text = ""
Dim db__1 As MongoDatabase = DB()
Dim ta As MongoCollection(Of Tapsa) = db__1.GetCollection(Of Tapsa)("tapsaas")
Dim array As New List(Of String)
array = divide(tx_texto.Text)
Dim cont As Integer = 0
Dim q = Query.All("_keywords", BsonArray.Create(array))
For Each obj As Tapsa In ta.Find(q)
tx_resultado.Text &= obj.codigo & " " & obj.texto & vbCrLf
cont = cont + 1
Next
lb_cantidad.Text = cont
End Sub
Como puedes ver en el código, creamos la conexión a mongo, luego sobre el texto ingresado aplicamos la misma regla de eliminar las palabras “cortas” de menos de dos letras utilizando la misma función divide. Una vez que el array esta listo , creamos una query, buscando en el campo keywords y transformando a un BsonArray nuestra lista de string (array), luego hacemos un foreach sobre todas los registros resultantes de la búsqueda. Si hacemos un watch sobre la query vemos lo siguiente:

Lo que corresponde a la misma consulta que habíamos ejecutado en el Shell (texto resaltado en amarillo, a 20cm de acá, hacia arriba
)
Y luego mostramos los resultados en el tx_resultado (textarea), en el ejemplo siguiente busqué izquierdo:

La cantidad es 2.338 registros, es un tiempo muy reducido de tiempo, obviamente este sigue siendo un numero muy elevado de registros como para presentarlos al cliente, solo es para efectos de demostración, en producción la lógica es distinta, sin embargo, lo que quiero mostrar el la forma de buscar datos de texto dentro de una colección mongoDB.
Como siempre, te puedes bajar todo el código, incluyendo los registros para que pruebes:

Para la explicación de como instalar mongoDB en tu computador, revisa el Post Anterior
Saludos!
@chalalo
Hola que tal, este tutorial lo estaba preparando hace un tiempo atrás, pero por cosas del destino, venia trazado con esto. Es esta oportunidad, vamos revisar un completo (quiero creerlo, aunque no es tan completo), caso de uso de MongoDB con ASP.NET MVC. Quiero aclarar primero que este articulo es parte de mi aprendizaje con MongoDB, no soy un experto, de hecho, espero que expertos critiquen mi trabajo de manera de aprender más, es decir, este articulo esta hecho con la excelente metodología “aprender haciendo”, y no enfurecerse por los errores.
Pero estoy seguro que nadie quiere leer mis penas, si no el artículo, veamos el contexto de la aplicación: “Un sencillo (paupérrimo) sistema de Blog, en donde se puedan ingresar post y se pueda además agregar comentarios a ese post.” Si lo vemos en más detalle:
Página Principal
 | 1) Ingreso de el Post a MongoDB, por un tema de ahorrar código, no hice las validaciones para el ingreso. Los Tags puedes separarlos por espacios, puntos o punto y coma. 2) Listar todos los Post que se han ingresado, mostrando como link el título y luego la fecha de publicación. El link nos enviará a la página de detalle y allí se mostrará el texto del post. 3) Se muestran la cantidad de comentarios asociados y la lista de tags ingresados, separados por ; 4) Posibilidad de borrar el Post, si bien no tiene mucho sentido hacerlo acá, es por mostrar la funcionalidad. |
Página Detalle
 | 1) Mostrar el Titulo y el texto ingresado para el Post 2) Al igual que la página anterior mostramos la lista de tags separados por punto y coma. 3)Formulario para el ingreso de comentarios, esta vez usé solo input type=”text”, no quise usar textarea, solo por diseño. Al igual que la pantalla anterior, no tengo validada las entradas, por un tema de simplicidad. 4) Listado de Comentarios asociados al post, cada vez que ingresamos uno comentario, se refleja en esta lista.
|
Todo esto lo haremos almacenando los datos en MongoDB, así que vamos por parte
Parte 1 – MongoDB
¿Que es MongoDB?
Es un sistema de Bases de datos OpenSource, multiplataforma basado en Documentos JSON, de esquemas libres, lo que significa que cada registro puede tener un esquema de datos distinto, es decir, que una colección puede contener registros con distintas estructuras. Las características más relevantes, (además de que es OpenSource), son la velocidad (es muuuy rápido) , su capacidad para soportar ambientes de alto rendimiento y su motor de consultas, simple y poderoso. Te recomiendo que veas los siguientes links para profundizar:
http://www.genbetadev.com/bases-de-datos/una-introduccion-a-mongodb http://www.4tic.com/blog/2011/06/29/mongodb-la-mysql-del-nosql/ Instalación de MongoDB en Windows 7
Primero que nada, tenemos que descargar MongoDB desde el WebSite del proyecto: http://www.mongodb.org/downloads , como puedes ver tienes la posibilidad de descargarlo para bastantes plataformas.
Descarga y descomprime el Zip 32-bit. El compilado "Production" es el recomendado.
Descarga y descomprime el Zip 64-bit
Te recomiendo descomprimir el archivo y cambiar el nombre de la carpeta a algo más corto, por ejemplo, simplemente mongo.
Crear el directorio de Datos
Por defecto, MongoDB almacenará la data en la carpeta \db\data, pero esta no es creada automáticamente, por lo que debemos hacerlo nosotros.
C:\> mkdir \data
C:\> mkdir \data\db
Y listo!, ya tenemos instalado MongoDB. 
Levantar el server y conectarnos a él.
Los binarios importantes que están en la carpeta \mongo\bin son:
mongod.exe – que corresponde al servidor, prueba con mongod –help para las opciones mongo.exe – El Shell para administración En mi caso , entro a c:\mongo\bin\mongod.exe para correr el server:

Quizás esta opción de levantar manualmente el servidor no nos acomode, pero descuida, el manual para instalarlo como servicio lo puedes encontrar acá :http://www.mongodb.org/display/DOCS/Windows+Service
La consola de administración por defecto nos conecta al el servidor de MongoDB corriendo en localhost, y usa una base de datos llamada test, podemos ver más opciones para el arranque de el shell con mongo --help.

Luego descargue el Driver para C#, ya que vamos a programar la aplicación, yo descargué el MSI desde: https://github.com/mongodb/mongo-csharp-driver/downloads en mi caso la versión 1.3
Para ver una descripción de los comandos de administración del Shell puedes visitar http://www.mongodb.org/display/DOCS/Developer+Zone

Se instala en Archivos de Programa\MongoDB\CsharpDriver 1.3

Y estamos listos con la instalación y el driver. Luego obviamente tenemos que hacer la referencia en el proyecto MVC 3.

Parte 2 - Creación del Blog “La Preparación”
Vamos a utilizar 3 clases, Artículo, Comentario y Tag, el modelo de clases el siguiente:

Y el código:
using System;
using System.Collections.Generic;
using System.Web;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Bson;
namespace Blog.Models
{
public class Tag
{
public string tag { get; set; }
}
public class Comentario
{
[BsonId]
public ObjectId id { get; set; }
public string fecha { get; set; }
public string usuario { get; set; }
public string texto { get; set; }
}
public class Articulo
{
public Articulo()
{
Tags =new List<Tag>();
Comentarios = new List<Comentario>();
}
[BsonId]
public ObjectId id { get; set; }
public string titulo {get;set;}
public string texto { get; set; }
public string fecha { get; set; }
public List<Tag> Tags { get; set; }
public List<Comentario> Comentarios { set; get; }
}
}
Como puedes ver el Objeto Articulo contiene una lista de Tags y una lista de comentarios, quise a propósito tener objetos “más complejos” que una colección Key-Value simple, para colocarme en un escenario un poco más real y que sirve al amigo lector 
MondoDB automáticamente asigna un id a cada objeto, sin tener que nosotros agregar una propiedad, sin embargo por facilidad en el manejo y a manera de demo, voy a agregar un id propio, sin embargo, decoro el atributo con BsonId indicando así que es un id de tipo BSON (Propiedades de MongoDB). La fecha la dejé como string, no voy a hacer búsquedas sobre ella, hay un tema de performance de cuidado sobre los datetime y su conversión.
La Estructura del proyecto entonces, es la siguiente:

Parte 3 – Pagina de Ingreso de POST (Index.cshtml)
Veamos el Index.cshtml y revisaremos la implementación de las siguientes funcionalidades:
Ingreso de datos (Post y Tags) Listado de Post Contador de Comentarios Borrar Post
Primero que nada, vamos a ver el listado de datos, para eso veremos la acción del controlador y el método del modelo asociado:
Controlador
public ActionResult Index()
{
ArticulosModel model = new ArticulosModel();
ViewBag.Articulos = model.ObtArticulos();
return View();
}
Modelo
public IEnumerable<Articulo> ObtArticulos()
{
MongoDatabase db = Db();
MongoCollection<Articulo> Articulos=db.GetCollection<Articulo>("articulos");
return Articulos.FindAll().ToList<Articulo>();
}
La función de conexión devuelve un objeto MongoDatabase referenciando a la base de datos en la que estoy trabajando, en mi caso mydb, no es necesario que la crees antes, si no que mongoDB la crea onfly si es que no existe (lo mismo que las colecciones).
private MongoDatabase Db()
{
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase db = server.GetDatabase("mydb");
return db;
}
Ahora si analizamos el código del Modelo, podemos ver que primero creamos el objeto conexión a partir del método Db (El cual veremos a continuación). Luego obtenemos toda la colección con GetColletion, nota que la colección es tipada (Articulo), una MongoCollection de objeto articulo. Luego retornamos todos los registros (findAll), revisa la documentación de la api de CSharp http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial para obtener mas información.
En resumen, obtenemos toda la colección de “articulos”, con GetCollection<Articulo>(“articulos”), este último parámetro indica la colección dentro de MongoDB.
En el controlador retorna hacia la vista,en el diccionario dinámico ViewBag, la lista de artículos. Como puedes ver esta vista no es tipada, de todos modos podemos recorrer la lista fácilmente con un foreach. Dentro de este ciclo, vamos a tener otro foreach en donde vamos a recorrer la lista de tags (articuloItem.Tags).
Puedes notar que existen dos links, en los cuales se utiliza el helper @Url, el primero hace referencia a la Acción Detalle del Controlador Artículos, el cual nos envia a la vista de detalle, y el siguiente hace referencia a la acción Borrar del controlador Articulos. en estos Links ocupo el Id de Articulo como parámetro en la url, en las vistas y controlador lo vamos a tratar como un String y luego, al momento de acceder a la colección de MongoDB vamos a convertirlo a un ObjectID
<section id="listado">
<ul>
@foreach (Blog.Models.Articulo articuloItem in ViewBag.Articulos)
{
<li>
<p>
<a class="Titulo"
href="@Url.Action("Detalle", "Articulos",
new { Guid = articuloItem.id })">@articuloItem.texto</a>
<br />
(@articuloItem.fecha)</p>
@articuloItem.Comentarios.Count() Comentarios, Tags:
@foreach (Blog.Models.Tag tagItem in articuloItem.Tags)
{
<text> @tagItem.tag ;</text>
}
<p>
<a class="Borrar" href="@Url.Action("Borrar", "Articulos",
new { Guid = articuloItem.id })">
Borrar</a>
</p>
</li> }
</ul>
</section>
Lo anterior nos dibuja lo siguiente en pantalla:

Como vez, bastante fácil el recorrer la colección. Veamos ahora como se implementa la acción Borrar.
Acción Borrar
Controlador
public ActionResult Borrar(string Guid)
{
ArticulosModel model = new ArticulosModel();
model.Borrar(Guid);
return RedirectToAction("Index");
}
Modelo
public void Borrar(string Guid)
{
MongoDatabase db = Db();
db.GetCollection<Articulo>("articulos").FindAndRemove(Query.EQ("_id",
ObjectId.Parse(Guid)), SortBy.Ascending("id"));
}
Al igual que el ejemplo anterior, en el controlador, obtenemos la referencia a mongoDB, y luego obtenemos la colección, y de inmediato utilizamos el método FindAndRemove y le pasamos la query que compara equivalencia (EQ) del campo “_id”, y le pasamos el campo Guid parseado a ObjectId. No podemos pasar directamente sin parsear el Id, ya que la equivalencia no se cumpliría. Puedes ver la manera de almacer el id en la colección escribiendo db.articulos.find() en el shell, fijate que el campo Id es _id:

En resumen, esta sola línea de código permite obtener la colección filtrada mediante la query EQ, y a la vez, remover los elementos de ese filtro, es realmente fantástico que con una sola línea podamos hacer tanto sobre mongo.
Acción Detalle
Controlador
public ActionResult Detalle(string Guid)
{
if (Guid == null)
{
Guid = TempData["ObjId"].ToString();
}
ArticulosModel model = new ArticulosModel();
ViewBag.Id = Guid;
return View(model.Detalle(Guid));
}
Modelo
public Articulo Detalle(string Guid)
{
MongoDatabase db = Db();
return db.GetCollection<Articulo>("articulos").FindOneById(ObjectId.Parse(Guid));
}
De igual manera que para borrar un registro, se obtiene la colección y obtenemos mediante el método FindOneById (parseando el Id) un único registro el cual retornaremos al controlador Detalla y este a su vez a la vista tipada. El if que vez en el controlador lo utilizo para determinar el id si es que es la primera carga de la vista detalle o si es que se creó un nuevo comentario en la vista detalle, de manera de mantener del id.
Formulario de Inserción
Veamos el formulario, comentarios de CSS aparte (no soy diseñador, hago todo absolutamente horrible).

El código asociado a este formulario es el siguiente:
<section id="contenido">
@using (Html.BeginForm("Create", "Articulos",
FormMethod.Post, new { id = "formulario" }))
{
<label for="titulo">Título:</label>
<input type="text" id="titulo" name="titulo" />
<label for="titulo">Texto:</label>
<textarea id="texto" name="texto" rows="3" cols="40"></textarea>
<label for="tags">Tags</label>
<input type="text" id="tags" name="tags" />
<input type="submit" value="Grabar!" id="grabar" />
}
</section>
Muy simple la verdad, ahora veamos el Controlador y el Modelo
Controlador
[HttpPost]
public ActionResult Create(FormCollection form)
{
Articulo articulo = new Articulo();
articulo.titulo = form["titulo"];
articulo.texto = form["texto"];
articulo.fecha = Convert.ToString(DateTime.Now);
string tags = form["tags"];
char[] delimitadores = { ' ', ',', '.', ';' };
string[] TagsString = tags.Split(delimitadores);
foreach (String tagtexto in TagsString)
{
articulo.Tags.Add(new Tag() { tag = tagtexto });
}
ArticulosModel model = new ArticulosModel();
model.Insertar(articulo);
return RedirectToAction("Index");
}
Modelo
public void Insertar(Articulo articulo)
{
MongoDatabase db = Db();
MongoCollection<Articulo> articulos = db.GetCollection<Articulo>("articulos");
articulos.Insert(articulo.ToBsonDocument());
}
Nota que en el controlador, recibimos los objetos del formulario y los vamos asignando a un nuevo objeto Articulo, luego vamos separando los tags mediante delimitadores y los vamos ingresando a la lista de objetos tag de Articulo. Una vez que este listo el objeto, se lo pasamos al método del modelo para que lo inserte. Y nuevamente, crear la conexión, obtener la colección para luego insertar el articulo, parseado a una clase BsonDocument, que es con lo que trabaja MongoDB. El controlador nos devuelve a la acción Index, que nos va a recargar la vista.
Página detalle (Detalle.cshtml)
La página de detalle es una vista tipada, básicamente tiene el mismo funcionamiento que la página anterior, por lo que solo me voy a enfocar a las funcionalidades que varían.
Un tema importante para la funcionalidad del detalle, es agregar nuevos comentarios, esto implica obtener el objeto Articulo desde la colección y luego agregarle un nuevo objeto comentario, para posteriormente almacenarlo.
Veamos la inserción de un nuevo comentario:
Controlador
[HttpPost]
public ActionResult CrearComentario(FormCollection form)
{
ArticulosModel model = new ArticulosModel();
model.CrearComentario(form["id"].ToString(),
new Comentario()
{
usuario = form["usuario"].ToString(),
texto = form["comentario"].ToString(),
fecha = Convert.ToString(DateTime.Now)
});
TempData["ObjId"] = form["id"].ToString();
return RedirectToAction("Detalle");
}
Modelo
public void CrearComentario(string Guid, Comentario comentario)
{
MongoDatabase db = Db();
var articulos = db.GetCollection<Articulo>("articulos");
Articulo a = articulos.FindOneById(ObjectId.Parse(Guid));
a.Comentarios.Add(comentario);
articulos.Save<Articulo>(a);
}
En el controlador creamos el comentario, a partir de los datos obtenidos desde el formulario, recuerda que debemos almacenar en algún elemento de formulario el id del articulo, para obtener el elemento desde la colección, llamamos al método del modelo llamado CrearComentario y pasamos como argumento el nuevo objeto, luego retornamos a la acción detalle, lo que produce evidentemente una recarga de página y podremos ver la lista de comentarios actualizada. Es en esta acción donde utilizamos TempData para enviar el ObjId hacia la acción Detalle).
En el modelo, como ya habíamos dicho, obtenemos el articulo (objeto a), y agregamos el comentario a la lista de comentarios (a.Comentarios.Add(comentario)). Luego ( y con una facilidad fascinante) , simplemente guardamos el articulo con el método de MongoDB Save, indicando el tipo y el objeto que vamos a guardar.
En la vista, el formulario tiene el siguiente código, en el que puedes ver que tenemos un campo oculto con el Id, el cual es asignado al ViewBag en el controlador Articulo, en la acción Detalle. Veamos el código:
<p>
@using (Html.BeginForm("CrearComentario", "Articulos", FormMethod.Post, new { id = "formularioPost" }))
{
<label for="usuario">Usuario:</label>
<input type="text" id="usuario" name="usuario" required="true"
placeholder="Ingrese su Nombre:" />
<label for="comentario">Comentario:</label>
<input type="text" id="comentario" name="comentario"
required="true" placeholder="Ingrese Comentario:" />
<input type="submit" value="Comentar!" id="comentar" />
<input type="hidden" value="@ViewBag.Id" id="" name="Id" />
}
</p>

Luego, todos los comentarios ingresados son mostrador en la tabla siguiente:

Cuyo código es muy simple, recordemos que esta vista es tipada, por lo que podemos recorrer la colección de Comentarios fácilmente:
<ul>
@foreach (Blog.Models.Comentario comentarioItem in @Model.Comentarios)
{
<li>
<p>@comentarioItem.texto</p>
<p>Posteado el @comentarioItem.fecha By @comentarioItem.usuario</p>
</li>
}
</ul>
Puedes utilizar MongoVUE para visualizar los datos , en el caso que no te guste utilizar la Shell, descárgalo en http://www.mongovue.com/, yo descargué la versión gratis, aunque el producto no es caro, de hecho estamos evaluando el comprarlo, ya que ayuda bastante

Nos conectamos y podemos ver la colección y su estructura.

Nota que los comentarios tienen el _id 00000000000, debido a que no los estoy asignando en la creación del comentario, ya que no voy a hacer nada con esto, sin embargo, si vas a hacer filtros mediante los comentarios, es necesario que si tengan un Id asignado.
Descarga el ejemplo!! 

Sumario
No soy para nada un experto en MongoDB, simplemente dije “voy a investigar, hacer una aplicación de prueba, y escribir en el blog lo que aprendí”, y dicho sea de paso, proponerlo para la búsqueda entre miles de registros para un sistema en producción, para esto tenía que convencer a mi jefe para que diera el OK a utilizar MongoDB, y bueno, ese es tema aparte, pero lo aprobó 
Personalmente me sorprendió la rapidez, y su nueva filosofía, distinta a mis ojos que solo conocían bases de datos relacionales. La API de C# provee de prácticamente de todo lo necesario. Quizás puedo criticar la falta e ejemplos en C# o que yo soy malo para buscar información, justamente fue esto lo que me inspiró a escribir este pequeño tutorial, de manera de poder ayudar a los que andan tan perdidos como yo.
Seguramente hay gente que puede aportar mejorando este código, sea bienvenido, de esa manera yo también aprendo
Espero que te sirva!! y ya tengo otro articulo sobre búsquedas de texto, en VBNET y Mongo 
Saludos!


Hola que tal?, te cuento que estamos armando una iniciativa de compartir información acerca de este nuevo estándar de la Web. La URL es:
Como dice el sitio:
HTML5CL es un lugar de encuentro para que nosotros, los desarrolladores web compartamos información acerca de este nuevo estándar de la Web. Buscamos la manera de apoyarnos mutuamente fomentando el buen uso de las nuevas características mediante tutoriales, videos, aportes de todos. Entre todos hacemos este sitio!
Seguramente preguntas como puedo cooperar…
Puedes colaborar enviando tus aportes al correo electrónico contacto.html5cl@gmail.com, todo es bienvenido:
- WebCast
- ScreenCast
- Artículos
- Noticias
- Código con ejemplo ( es importante que adjuntes el código, de manera que todos puedan probar tus aportes)
El reconocimiento del material, siempre será del autor, es por eso que puedes especificar tu correo, Facebook, twitter, la url de tu propio sitio web, etc.
Esperamos tener una buena llegada con los desarrolladores. La cara visible de esta comunidad es tu mismo, con tus aportes.
---------
La idea es que todos cooperemos, en mi caso, fue un video sobre LocalStorage:
Espero que te animes a cooperar!
Saludos,
@chalalo
Hola, también les dejo los slides de la charla de HTML que dimos con el Maestro Miguel Ángel Sáez, agradezco a todos los buenos comentarios 
Recuerden lo del diplomado en HTML5 y el hashtag #HTML5CL para comenzar a armar comunidad e intercambiar información!
http://blogs.msdn.com/b/rmugar/archive/2011/11/11/diplomado-microsoft-fundamentos-de-html5.aspx
Saludos,
@chalalo
Hola, les comparto la presentación que utilicé para la charla de WebMatrix 2 en el TechDay 2011, recuerda que está disponible la academia MVA de WebMatrix en :
https://www.microsoftvirtualacademy.com/tracks/desarrollo-con-webmatrix
y que pueden descargar WebMatrix Beta 2 desde:
http://www.microsoft.com/web/webmatrix/next/
Las Slides!
Saludos!
@chalalo
(Extracto del Blog de Stephen Walter)
Se lanzó un nuevo release del ya famoso Ajax Control Toolkit, esta vez se introduce un nuevo control Ballon Popup y mejoras en el ya existente Control Tab, incluyendo el soporte de carga bajo demanda de cada pestaña y el soporte para navegación mediante teclado. Se ha solucionado los bugs más reportados en CodePlex.com
Puedes descargar este control desde el sitio de CodePlex.
http://AjaxControlToolkit.CodePlex.com
De manera alternativa y rápida se puede obtener esta versión del ACT utilizando NuGet simplemente abriendo la consola del Library Package Manager en Visual Studio 2010 y escribir:

Con el control ballonPopUpExtender puedes hacer lo siguiente ente otras cosas:


Con una configuración realmente fácil, especificando el TargetControlID al que se va a asignar el BallonPopUpExtender

Sobre las pestañas, mejor lo lees de la fuente, pero que puedes esperar? Antes el contenido de los tabs se cargaban al momento del redenrizar el control, lo que a toda vista puede generar un problema de performance o de vista de actualización de datos.
Revísalo en el blog de Sthepen Walther:
http://stephenwalther.com/blog/archive/2011/11/16/ajax-control-toolkit-november-2011-release.aspx
Actualmente ya hay bastantes plugins para JQuery que permiten utilizar efectos similares en nuestras páginas, sin embargo, si eres un programador WebForm te va a servir mucho esta nueva release.
Saludos!
@chalalo
Hola, acá les dejo el video del webcast de hoy sobre la relación de ASP.NET con HTML5 y CSS3, no apuntaba a ser algo muy técnico, más bien una conversación acerca de lo que está haciendo el team ASP.NET en Webforms y MVC.
Ahh trata de verlo en HD , vas a distinguir mejor el código y te advierto, dura 1 hora 20 minutos, para rato!
Saludos!
@chalalo
Hola que tal, una de las características que más me gustan en WebMatrix beta 2 son la autocompletación de código para PHP, funciones de WordPress y obviamente jQuery, pero la primera vez que lo baje, no me funcionó el intellisense de jQuery, pense que algo no estaba haciendo bien,y claro, hay que agregar la referencia al archivo de autocompletar. Creo que eso tiene lógica, debido a que este archivo, que es el mismo que se utiliza en Visual Studio, se puede actualizar tan rápido como versiones de jQuery están siendo liberadas, ( y están liberando versiones con mucha frecuencia!)
Primero que nada, descarga la versión de vsdoc desde http://www.asp.net/ajaxlibrary/cdn.ashx , en mi caso seleccione la 1.7.

Luego la agregar a tu proyecto, a continuación agregar la referencia al archivo en donde quieres que funcione la autocompletación:
/// <reference file="jquery-1.7-vsdoc.js" />
y listo, ya tienes Intellinsense para jQuery en WebMatrix Beta 2
Y si no tienes WebMatrix, descárgalo ya!
http://www.microsoft.com/web/webmatrix/next/
Saludos,
@chalalo
Están abiertos los registros para el evento TechDays 2011, tengo el agrado de participar como orador, sobre temas de HTML5 y WebMatrix, espero que nos veamos allá 
Evento de la Mañana:Orientado a Profesionales (Infraestructura y Desarrollo) que trabajen en el área Informática dentro de una empresa. Abordará temas de Innovación, Entornos de Trabajo flexibles, Valor de negocios, Reducción de costos, Nuevas tendencias (computación en la nube, consumerización de TI, etc.).
Yo estoy a las 10:40 junto a Miguel Ángel Saez hablando de HTML5,CSS y Javascript

Evento de la tarde:Para Desarrolladores o Profesionales de TI independientes, Emprendedores, o Estudiantes de informática interesados en temas de Desarrollo web, de Videojuegos, Desarrollo móvil, Computación en la nube, Virtualización, Administración y Soporte de equipos,etc.
Estoy a las 17:00 horas junto a Maximiliano Marín hablando sobre WebMatrix 2

Nos vemos!
Saludos,
Gonzalo
Hola que tal, hoy voy a hablar sobre una muy buena característica que nos trae ASP.NET 4.5. Para situarnos en el contexto, hablemos de optimización, ASP.NET nos ha dado mecanismos de optimización en el front-end y back-end. Técnicas de agrupación y Minificación ya eran posibles de aplicar en ASP.NET, sin embargo, no con la facilidad y flexibilidad que nos presenta ASP.NET 4.5 Developer Preview , la cual introduce bundling(Agrupación o combinación), que nos permite combinar múltiples archivos JavaScript para una carga más rápida al evitar request por cada uno de los archivos js, y aplicando minificación, que reduce considerablemente el tamaño de los archivos JavaScript y CSS removiendo los caracteres innecesarios.
Veamos como funciona, para esto veamos la estructura típica de un proyecto ASP.NET WebForm:

El archivo index.aspx está simplificado al máximo solo para efectos demostrativos, veamos el código:

Como ves, solo tenemos la carga de los CSS y los Scripts, al momento de ver las peticiones request de la página veremos:

Nos podemos dar cuenta de la forma de la carga de los archivos, tenemos 9 peticiones y 137KB.
Veamos ahora la nueva característica de ASP. NET 4.5, que permite reducir el numero de request combinando los archivos JS en uno solo, al igual que los archivos CSS, los cuales son minimizados automáticamente.
Primero que nada debemos hacer referencia ahora a las carpetas en donde se encuentran los script y estilos:
<link href="Styles/css" rel="stylesheet" type="text/css" />
<script src="Scripts/js" type="text/javascript"></script>
Y en el globlax.asax, agregar en el método Application_Start la combinación por Default (EnableDefaultBundles)
<%@ Import Namespace="System.Web.Optimization" %>
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
BundleTable.Bundles.EnableDefaultBundles()
End Sub
Ahora en tiempo de ejecución automáticamente se combinará y minimizarán los archivos JS y CSS, veamos:

Wow!!!, El CSS minimizado y el JS minimizado, él tamaño total del request es 80KB, pero una aclaración, debes eliminar todos los archivos que nos vas a ocupar en producción, como por ejemplo, los ya minimizados, por que ahora ya no estas discriminando por archivo referenciado desde tu página, si no que es toda la carpeta Script, lo mismo para los CSS, además deben estar bien formateados o la minificación falla.
Para comprobar esto, podemos ver la respuesta del request al recurso CSS Minimizado

Ahora también puedes crear tu propio Bundling en el archivo globlal.asax, para CSS con CssMinify o para JavaScript JsMinify y agregrando los archivos que serán combinados y minimizados con su ruta relativa.
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
BundleTable.Bundles.EnableDefaultBundles()
Dim cssBundle = New Bundle("~/Content/css", GetType(CssMinify))
cssBundle.AddFile("~/Styles/css1.css")
cssBundle.AddFile("~/Styles/css2.css")
cssBundle.AddFile("~/Styles/css3.css")