Everything: Una herramienta productiva.

17 11 2009

Existe una multitud de herramientas, plugins para Visual Studio, editores, y demás que nos asisten a la hora de desarrollar. Yo particularmente soy amigo de las más sencillas, ya bastante con aprender todos los vericuetos del entorno.

Entre estas herramientas que me “conquistaron”, la que más me gusta es Everything, Un buscador de archivos. No hace nada que no se pueda hacer con Windows o con muchas otras herramientas que realizan la misma tarea y ofrecen mucha más funcionalidad, básicamente escribimos partes del nombre del cualquier archivo separadas por espacios y nos muestra una lista de todos los que coinciden con el patrón buscado.

¿Por que vale la pena entonces? El secreto de Everything es que lo que hace lo hace bien, es gratis (vale donar ¡eh!), consume escasos recursos y es muy, muy, MUY rápido.

Busqueda en Everything

El secreto: Respuesta inmediata.

Para ser claro, a la pulsación de cada tecla tendremos nuestra lista de archivos filtrada. Para escanear todo el disco rígido por primera vez solo tarda unos segundos, y los cambios que se hagan a los archivos, afectan los resultados de Everything en tiempo real.

Ahora, si trabajan en proyectos con cientos o miles de archivos créanme que con un poco de uso de Everything se van a olvidar de navegar por árboles infinitos de carpetas y listas interminables de archivos. Abrir un archivo en Visual Studio se convierte en activar el Everything con un shortcut, escribir unas letras y presionar enter.

Unos pocos tips para su uso:

  • Incluirlo entre los programas de inicio, pesa muy poco e inicia sin que lo notemos.

    Setear HotKey

    La única configuración necesaria: el HotKey.

  • Setear un shortcut, no viene por defecto y es uno de los secretos para su uso, yo uso Windows + S. (Se agrega en: Tools – General – New Windows HotKey Modifier / Key)
  • Excluir las carpetas sobre las que no queremos resultados: (Tools – Exclude / Volumes)
  • Si queremos buscar dentro de una carpeta específica, la escribimos antes del nombre del nombre del archivo seguida de barra invertida. (“MiProyecto\  app.config”)
  • Si trabajan con varios entornos abiertos, asegurensé de tener el foco sobre el que quieren abrir el archivo buscado antes de activar Everything.

¡Extra, Extra!

Everything tiene como extra unas pocas pero poderosas funcionalidades.

Permite exponer un disco o carpetas seleccionadas con Everything actuando como un mini web server, pudiendo hacer busquedas desde otra máquina mediante un browser ¡y bajarse los archivos encontrados!

Podemos exponer parte de nuestros archivos por HTTP. ¡Usar con responsabilidad!

Posee un protocolo propio (ETP: Everything Transfer Protocol) que nos permite setear una instancia Everything como servidor y utilizar otras como clientes de búsqueda, con la misma funcionalidad que usándolo en forma local. Fantástico.

Si quieren hilar fino se puede configurar para usar Regular expressions, permite exportar a un archivo de texto la lista de archivos encontrados, y tiene multiplicidad de opciones que vienen configuradas como para no tener que tocarlas.

Asique ya saben, basta del perro de XP y de la (mucho mejor pero igualmente) no muy efectiva barra de búsqueda de Vista, no tienen nada que hacer al lado de Everything. Después me cuentan.

links: Everything





Sobre base64. Para que usarlo, para que no, y como manejarlo en .net y Asp.Net

6 11 2009

¿Que es base64?

Base64 no es en principio otra cosa mas que un sistema numérico, el cual debido a sus características se emplea en muchos ámbitos de la informática para representar información binaria.

Todos los sistemas de numeración tienen una lista de símbolos que utilizan para representar valores, por ejemplo:

Binario: ’01’
Decimal: ‘0123456789’
Hexadecimal: ‘0123456789ABCDEF’
y para base64 el conjunto es:
‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/’

Como vemos, es un subconjunto de ASCII, y tiene como particularidad que todos sus caracteres son imprimibles, de hecho 64 es la mayor potencia de 2 que permite ser representada por un subconjunto de caracteres ASCII imprimibles, por eso, si pasamos cualquier información a su representación de base64, tenemos la seguridad de que no tendremos problemas al transmitirla, almacenarla o leerla, incluso aunque esta contega los más remotos caracteres unicode, una imagen o un mp3, ya que para convertir algo a base64 trataremos directamente con los bits.

¿Como codificamos en base64?

Veamos (en este ejemplo flagrantemente robado de Wikipedia) como se codifica la palabra “Man”.

Texto de entrada M a n
ASCII 77 97 110
Bits 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
Índice 19 22 5 46
Resultado en Base64 T W F u

Tenemos que la M es en ASCII el caracter 77 (01001101 en binario), y como el primer paso para nuestra tarea es convertir la información de origen en bits (más sobre esto en un momento), transformamos toda la cadena en una secuencia de unos y ceros, los cuales tomamos en grupos de a seis.

El primero de estos grupos (010011) representa 19, y si tomamos la posición 19 en la lista de símbolos de base64 (empezando a contar desde cero, claro) obtenemos la T, y continuando con este algoritmo llegamos al resultado “TWFu”.

Caracteres de Relleno

base64 se codifica tomando los bytes de tres como entrada en cuatro sextetos, o sea de a 24 bits. Cuando esta cantidad no coincide, completamos con el caracter de relleno “=” los sextetos restantes.

Por ejemplo, si hubiéramos codificado solamente el texto “Ma”, veríamos que no coincide la cantidad de octetos con la de sextetos, luego de “TW” me quedaría 0001, por lo que completo con ocho ceros y obtengo “TWE”. El sexteto vacío que queda se completa con el caraceter “=” quedando como resultado: “TWE=”

Hasta aquí como se codifica. De la misma manera, podría codificar un archivo ejecutable, una imagen, archivos de sonido o simplemente como en este caso, Texto Plano.

Ooops, acabo de decir “texto plano”, pero como bien dice Joel Spolsky (parafraseando a famoso economista que parafraseaba a conocido escritor de ciencia ficción): “No existe tal cosa como el texto plano”. Y acá es donde entra a fastidiarnos la palabra “Encoding”.

Encoding

La representación lógica de una cadena de texto, como puede serlo un String de .net, se puede convertir a bits de muchas maneras. No es lo mismo la representación binaria de texto en ASCII que en Unicode, al respecto recomiendo encarecidamente leer el citado post de Joel Spolsky, pero lo que quiero destacar ahora a los efectos prácticos de comprender el código es que, cuando trabamos con texto, este es para nosotros la representación lógica de la información, la cual se perderá al momento de trabajar directramente con los bits, y como la conversión de esta información lógica a bits puede realizarse de muchas maneras distintas, debemos tener control de este paso al momento de codificar y decodificar texto en y desde base64.

Base64 en .net

Para convertir texto a bytes .net nos ofrece la clase abstracta Encoding y sus derivados concretos, en el ejemplo utilizaremos UTF8Encoding. Si no necesitamos usarlas en grandes iteraciones, podemos obtener instancias de estas clases desde las propiedades estáticas que nos da la clase Encoding, (.UTF8, .UTF7, .ASCII).

Y para obtener los bytes utilizamos el método GetBytes, dado un string “s”:

Encoding.UTF8.GetBytes(s)

Estos bytes se los pasamos a Convert.ToBase64String:

String b64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(s));

y a la inversa, mediante el método GetString de la misma clase de Encoding que hayamos utilizado en la conversión:

String s = Encoding.UTF8.GetString(Convert.FromBase64String(b64));

URLTokenEncode, base64 en ASP.NET

Utilizar parámetros codificados en base64 en un query string nos aporta la seguridad de que no tendremos problemas con los caracteres reservados por HTML, así como la ofuscación de la información ante los usuarios, pero nos encontramos ante el problema de los símbolos “+”, “/” y “=” que tienen un significado dentro de una URI.

Ante esta limitación .net nos da una alternativa a la codificación clásica mediante el método estático UrlTokenEncode de la clase HttpServerUtility, en System.Web:

String b64=HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(s));
String s=Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(b64));

Con este método, los caracteres “+” y “/” son reemplazados por “-“ y “_” respectivamente y los simbolos “=” de complemento se reemplazan por un dígito numérico indicando la cantidad de los mismos, de esta manera la cadena “ûï¾x%óaxz” se códifica (en UTF8) como: “w7vDr8K+eCXDs2F4eg==” según el método estándar y con UrlTokenEncode “w7vDr8K-eCXDs2F4eg2”, donde el “2” final representa los “==” al final del resultado estándar y el “-“ reemplaza al “+”.

De esta manera obtenemos una cadena totalmente segura para utilizar en el ámbito web.

Algunos hechos sobre base64

  • Base64 no es un método de encriptación. Si bien ofusca la información ante la simple vista no hace falta mucho conocimiento ni pericia para recuperar la información original.
  • Base64 “pesa” un 33% más que la información original. Esta ralación está dada por la relación 8 a 6 bits por caracter, (o sea, un caracter de base64 representa menos información que un caracter normal).
  • Aparte del nombrado Issue en su utilización en Web, en otros ámbitos también hay caracteres que se tornan problemáticos, por ejemplo en regular expressions, se suelen reemplazar “+” y “/” por “[“ y “]”. Observesé que la codificación que utiliza UrlTokenEncode no serviría en este caso ya que los “+” tienen significado propio en Regular Expression, por lo que habría que escaparlos.
  • Insisto: No sirve para encriptar información. No utiliza claves ni certificados, la conversión a la información original es prácticamente directa y no está pensado para este fin.
  • Si podemos, en cambio, utilizarlo para guardar o transmitir información previamente cifrada que suele presentar caracteres problemáticos para ser transmitidos o almacenados.




Diferencia entre Find y Filter en jQuery

15 07 2009

jquery_thumbEs muy común confundirse entre estos dos métodos al comenzar con jQuery, pero ambos realizan tareas muy distintas.

Mientras .filter quita, de los elementos contenidos en el objeto $, los que no cumplan con el selector que se le indica, .find busca en los descendientes de los objetos seleccionados.

$("div.nav").find("a") Encuentra los links dentro de cualquier div con la clase css nav, en cambio:

$("a").addClass(".link").filter("[href^=http://]").addClass(".externo"); Agrega la clase “link” a todos los <a> y la clase “externo”, solo a los que poseen una valor para el atributo href que comienza con “http://”, Este es otro ejemplo clásico de jQuery. (Los corchetes se utilizan para buscar en atributos del HTML y el ^ indica el que la cadena buscada debe estar al comienzo del valor del atributo.)

En general .filter se utiliza para trabajar con un subconjunto de otro conjunto sobre el ya realicé una acción, permitiéndonos encadenar varias sentencias en una como en el ejemplo.

En cambio .find es un método muy poderoso que me sirve para navegar dentro del DOM por relaciones “descendiente de” entre elementos. Buscará en los elementos descendientes de los contenidos en $, sin tener en cuenta estos últimos.

Por ejemplo, dado:

<div id="padre">
   <div id="hijo1">
      <div id="nieto1"></div>
   </div>
   <div id="hijo2"></div>
</div>

$("#padre").find("div") Encuentra “hijo1”, “hijo2” y “nieto1”, (y no el div “padre” contenido en el objeto $.)

Este tipo de métodos denominados “transversales”, son los que nos ampliarán el campo de acción cuando excedamos las posibilidades de los selectores.

¡Hasta pronto!





Checkear todos los CheckBox con jQuery

17 06 2009

Uno de los artículos más consultados de este blog explica como configurar una tabla para que al clickear en un Checkbox en la cabecera de una columna, todos los checks de la misma tomen el mismo estado “checked/unchecked”.

Sin embargo, ese código requiere de algunas condiciones:

  • La tabla debe poseer un ID.
  • Cada checkbox debe ser el primer elemento de la celda.
  • Hay que escribir una llamada al evento onclick del checkbox en la cabecera, pasando como parámetro el ID de la tabla, ya sea escribiéndolo o navegando por el DOM para obtenerlo.

Y tiene un grave problema, no funciona en navegadores no-IE.

Cuando empecé a investigar jQuery, quise emular como práctica este código y me encontré con que jQuery nos lleva a plantear una solución mucho mas completa, que no solo resuelve todos los problemas anteriores, si no que nos lleva a escribir en el body la cantidad de javascript: ¡cero!.

Vamos al grano:

Primer paso: Agregar el include del archivo js donde está el código. (aparte del de jQuery por supuesto)

<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/miScript.js" type="text/javascript"></script>

Segundo y último paso: En miScript.js el siguiente código:

$(function() {
    $("table th :checkbox").click(function() {
        $(this).closest("table")
            .find("td:nth-child(" + ($(this).closest("th").prevAll().size() + 1) + ") :checkbox")
            .attr("checked", $(this).attr("checked"));
    });
});

Aparte de esto, solo nos queda asegurarnos de que los checkbox de la cabecera estén en un TH y no en un TD.

Ahora ya no nos importa si usamos un GridView, una tabla estática, ni si posee tags THEAD y TBODY o solo TRs, ni si el checkbox es un control de servidor o simple HTML. Todos los checkboxs que tengamos en la cabecera (TH) de una tabla provocarán al cambiar su estado que cambien todos los de la misma columna.

No se a Uds. pero a mi me parece fantástico que solamente incluyendo un tag para jQuery y otro para un .js con el script (que seguramente ya estoy incorporando a nuestras páginas para utilizar otras funciones), tenga el problema resuelto en todas las páginas sin hacer más que olvidarme del tema.

Respecto al código, voy a usarlo como parte de la continuación de mi artículo anterior de introducción a jQuery para los que quieran entenderlo.

Nota: Debido al uso de la (excelente) función closest el código requiere jQuery 1.3+.

Saludos: Alejandro





Introducción a jQuery

8 05 2009

He estado usando un poco jQuery y, por si después de lo que ya había visto hacía falta algo más, me terminé de convencer de que jQuery es una tremenda ayuda para quienes programamos mucho o poco en JavaScript. Este es el primero de una serie de artículos introductorios los que voy a tratar de mechar con otros con ejemplos reales. Ahí vamos:

¿Que es jQuery?

Una biblioteca javascript (un .js de 19k en su versión de producción) que tiene las siguientes características:

  • Todo lo que hagamos con jQuery es “Browser-Agnostic”, o sea ¡funciona igual en todos los navegadores!
  • Adhiere al concepto de Unobstrusive javascript, o sea, “No metas javascript en tu HTML”, esto abarca los eventos en los tags y absolutamente todo lo que tenga que ver con javascript en el body, así como la mayoría de los <script> en el head, si no todos. Esto entre otras cosas facilita mucho la separación de tareas entre programador-diseñador.
  • Es OpenSource y al mismo tiempo posee cierto soporte de Microsoft, lo que incluye una versión con Intelisense y la inclusión por defecto en el nuevo  ASP.NET MCV.
  • Una comunidad importantísima, una enorme documentación y cantidad de tutoriales. Unas cuantas de estas cosas están en español.
  • Es extensible y posee una cantidad enorme de Plugins desarrollados, donde “enorme” quiere decir que en el sitio oficial hay más de mil.
  • Posee poderosos métodos para trabajar con Ajax.
  • Muchos efectos gráficos incluidos para manipular los objetos de nuestra página.

También presenta tres conceptos que definen la sintaxis de jQuery y gran parte de su funcionalidad:

  1. Utiliza en su sintaxis el concepto de encadenamiento de sentencias, (A.K.A. fluent interfaces o “chaining”), que nos permite realizar una gran cantidad de acciones en una sola sentencia y nos evita declarar infinidad de variables.
  2. Posee un conjunto de selectores muy poderoso con los cuales podemos recorrer el DOM a gusto y piaccere.
  3. Posee una sintaxis para trabajar con eventos que permite no tener que introducir llamadas a los mismos en los tags y en increíblemente flexible.

Estas características son las que veremos a lo largo de estos introducctorios, pero primero empecemos de cero:

Incorporando jQuery a nuestras páginas

En el sitio oficial: www.jquery.com podemos bajar la biblioteca en sus versiones de desarrollo, producción (minified) y visual studio, está última es una versión comentada que permite el intelisense. El sitio también es referencia en cuando a información se refiere.

Una vez incluido el archivos .js en nuestro proyecto, arrastramos el mismo al tag head de nuestra página, lo que genera lo siguiente:

<script src="js/jquery-1.3.2.min.js" type="text/javascript"></script>

para la versión minified 1.3.2, la actual al momento de escribir esto. (No hay que olvidar cambiar la versión de desarrollo por la de producción cuando ya no la necesitamos y no es mala práctica renombrar el archivo a jQuery a secas para facilitar el cambio de versiones.)

El objeto jQuery ($):

Casi toda la funcionalidad de jQuery está contenida en un objeto llamado también jQuery. Este objeto tiene un alias que es el símbolo $, o sea que en cada lugar donde escribimos $ podemos cambiar por jQuery y viceversa. Como el símbolo $ es el estandar vamos a verlo así escrito en este artículo. Veamos la estructura de una típica sentencia jQuery:

$("selector").acción(parámetros);

$(“selector”) captura, a partir del selector indicado, el conjunto del DOM identificado sobre el cual aplicamos la acción, pero el valor de retorno no es directamente un array de objetos, sino que es el propio objeto $ conteniendo los objetos en su interior.

Cuando ejecutamos un método sobre el objeto $ que contiene los elementos que seleccionamos, este aplica dicha acción a cada uno de los objetos recuperados. Un ejemplo concreto:

$("#mensaje").fadeOut(3000);

Llama para el elemento con id=”mensaje” a la función fadeOut, que aumenta su transparencia hasta hacerlo desaparecer al cabo de los tres segundos indicados como parámetro.

La función .ready

Ya tenemos un pequeño ejemplo de código jQuery, pero ¿donde lo ponemos?

Si leímos bien, una de las características de jQuery es que nos permite no introducir llamadas a funciones javascript en los tags HTML, más tarde vamos a ver como atachar eventos a los objetos del DOM, pero hay un método para ejecutar código en la carga de la página y que veremos hasta en la sopa, la función ready.

Normalmente cuando queremos ejecutar una rutina js en la carga de la página, utilizamos el evento onload del body, pero esto tiene la desventaja de hacernos esperar hasta que se carga toda la página, imágenes inclusive. jQuery nos presenta un camino alternativo que es la función ready, está se ejecuta ni bien el navegador levanto el DOM en memoria, ¿y que hace? bueno, lo que nosotros querramos, ya que toma como único parámetro un callback, o sea, una función javascript, veamos la sintaxis:

$(document).ready(
	function() { ... }
);

Como vemos ready es una función del objeto $, el cual en este caso ha sido creado a partir del document. Como parámetro de ready, estamos enviando una función cuyo código será el que se ejecute correctamente. De esta manera si quisieramos cumplir con la inutil misión de que el código del ejemplo anterior se ejecute en primera instancia al cargar la página, tendríamos que escribir lo siguiente:

<script type="text/javascript">
$(document).ready(function() {
   $("#mensaje").fadeOut(3000);
});
</script>

Donde hemos reemplazado únicamente los “…” por nuestra función.

En mucha de la documentación más vieja se ve esta sintaxis, pero jQuery presenta una abreviación que es la que vamos a usar:

<script type="text/javascript">
    $(function() {
    	$("#mensaje").fadeOut(3000);
    });
</script>

Hasta aquí hemos visto solo la manera de hacer de forma interesante algo muy inútil, y es que en la gran mayoría de documentos introductorios a jQuery verán que se presenta la librería haciendo uso de fadeIn, fadeOut y varias funciones gráficas que son muy impactantes a la vez que sencillas de utilizar. He estado hace unas semanas en una charla de jQuery donde toda la atención la despertaba este tipo de funcionalidad y en el mismo sitio oficial se presenta la librería con un lindo efecto.

Todo eso está genial, pero si Uds, como yo, nacieron sin la parte del cerebro que se utiliza para el diseño, antes de creer que jQuery es un compendio de efectos o de hacks para algunas funcionalidades, sigan leyendo y encontrarán un tesoro de la mano de la manipulación del DOM, los selectores, el encadenamiento de sentencias, la facilidad para trabajar con AJAX, el manejo de eventos y el crossbrowsing real, por sobre otros instrumentos no tan útiles a la hora de programar comportamientos y manejo de datos en la UI.

Saludos.





Atachar procesos automáticamente con macros de Visual Studio

16 07 2008

La manera de atachar un proceso a Visual Studio es clasicamente mediante ‘Debug – Attach to process’ o el más productivo Ctrl + Alt + P, y luego seleccionar el o los procesos que querramos depurar.

En desarrollos medianamente importantes es muy probable que debamos realizar este procedimiento repetidas veces para depurar un proyecto fuera de la interface de usuario, expuesto mediante una capa de servicios, llámese WS, remoting, WCF, etc. Ni hablar del worker process de ASP.NET,  ‘aspnet_wp.exe’. También es común que corramos un proyecto desde fuera del Visual Studio para evitar la compilación, y luego lo atachemos al IDE.

Entonces, si los procesos que atachamos son siempre los mismos, ¿por que no automatizar la tarea?, bueno, la solución que propongo es una macro de Visual Studio que haga este trabajo, atachando con un atajo de teclado todos los procesos que sean necesarios.

Para incluirla en VS, vamos al editor de macros (Alt + F11), agregamos un nuevo módulo y reemplazamos el contenido por el siguiente:

Imports System.Collections.Generic
Imports EnvDTE
Imports EnvDTE80
Imports System.Text

Public Module DebugMacros

    Private Enum EnumAction
        ResultOK
        ReRunWithDisatach
        Abort
    End Enum

    Public Sub AttachProcs()
        Dim ProcessList As New List(Of String)
        ProcessList.Add("InterfaceUsuario.exe")
        ProcessList.Add("MiServiceLayer.exe")
        AttachProcs(False, ProcessList)
    End Sub

    Private Sub AttachProcs(ByVal detachAll As Boolean, ByVal ProcessList As List(Of String))

        If detachAll Then DTE.Debugger.DetachAll()

        Dim isOK As EnumAction = EnumAction.ResultOK
        Dim sbErrorResult As New StringBuilder

        For Each proc As String In ProcessList
            Dim match As Boolean = False
            For i As Integer = 1 To DTE.Debugger.LocalProcesses.Count
                If DTE.Debugger.LocalProcesses.Item(i).Name.EndsWith(proc) Then
                    match = True
                    Exit For
                End If
            Next
            If Not match Then
                sbErrorResult.Append("El proceso '" + proc + "' no se está ejecutando." + vbCrLf)
                isOK = EnumAction.Abort
            End If
        Next

        If isOK = EnumAction.ResultOK Then
            'Desatacho todos los procesos
            Dim dbg2 As EnvDTE80.Debugger2 = DTE.Debugger
            Dim trans As EnvDTE80.Transport = dbg2.Transports.Item("Default")
            Dim dbgeng(1) As EnvDTE80.Engine
            dbgeng(0) = trans.Engines.Item("Managed")
            Dim proc2 As EnvDTE80.Process2
            For Each processName As String In ProcessList
                Try
                    proc2 = dbg2.GetProcesses(trans, ".").Item(processName)
                    proc2.Attach2(dbgeng)
                Catch ex As Exception
                    If ex.Message.EndsWith("8971001E") Then
                        sbErrorResult.Append("Error atachando " + processName + ". " + "El proceso ya se encuentra atachado" + vbCrLf)
                        isOK = EnumAction.ReRunWithDisatach
                    Else
                        sbErrorResult.Append("Error inesperado atachando " + processName + ". " + ex.Message + vbCrLf)
                        isOK = EnumAction.Abort
                    End If
                End Try
            Next
        Else
        End If

        Select Case isOK
            Case EnumAction.Abort
                DTE.Debugger.DetachAll()
                MsgBox(sbErrorResult.ToString + vbCrLf + "No se ha atachado ningún proceso", MsgBoxStyle.OkOnly, "Error al atachar proceso")
            Case EnumAction.ReRunWithDisatach
                If MsgBox("Hay procesos previamente atachados. ¿Desea reatacharlos?", _
                                    MsgBoxStyle.YesNo, "Atachar Proceso") = MsgBoxResult.Yes Then
                    AttachProcs(True, ProcessList)
                    Exit Sub
                End If
            Case EnumAction.ResultOK
                Dim Resultado As New StringBuilder
                For Each s As String In ProcessList
                    Resultado.Append(s + vbCrLf)
                Next
                MsgBox("Se han atachado los siguientes procesos: " + vbCrLf + Resultado.ToString, MsgBoxStyle.OkOnly, "Proceso atachados")
        End Select
    End Sub

End Module

Observar que en AttachProcs() hay una colección con los nombres de los procesos la cual hay que editar de acuerdo a nuestras necesidades.

Ahora solo falta asignarle una combinación de teclas, desde Tools – Options – Keyboard, filtramos por “Macro” o “AtachProcs” y una vez ubicada la macro le asignamos una combinación de teclas.

Ahora solo basta correr los procesos por fuera de Visual Studio y atacharlos con la combinación de teclas.

Si el código encuentra alguno de los procesos atachado, desatacha todos los procesos e intenta nuevamente.

Nota: Este simple código está hecho a partir de la grabadora de macros (Tools – Macros – Record Temporary Macro), recordemos que todo lo que hacemos en VS queda registrado en la grabadora y que casi todo en el entorno es un objeto que se puede manipular.





Depurar sin complicarnos la vida utilizando Debugging Attributes

29 05 2008

Cuando depuramos con Visual Studio es un verdadero fastidio el hecho de tener que entrar a todos los métodos o propiedades que se encuentran dentro de una llamada, por ejemplo:

void MiMétodo(DameUnString())
{
   //algo acá que si quiero depurar
}
String DameUnString()
{
   //¡No quiero depurar esto!
   return "Este es tu String!";
}

DebuggerStepThrough y DebuggerHidden

Cuando se trabaja en cualquier sistema medianamente complejo es muy molesto depurar código como el anterior ya que no hay manera en VS de indicar que queremos ir directamente al cuerpo del método que estamos por depurar, sin entrar a cada parámetro.

Lo mismo ocurre cuando presionamos por error F11 en vez de F10 y entramos a un interminable método que nos obliga a poner un break al final (y luego a quitarlo para no parar nuevamente)

Una solución parcial pero util son los atributos DebuggerStepThrough y DebuggerHidden.

Poniendo DebuggerHidden a un método logramos que Visual Studio no pase nunca por el método:

[System.Diagnostics.DebuggerHidden]
String DameUnString(){...}

hará que nunca depuremos el método DameUnString.

En cambio con el más util DebuggerStepThrough, el entorno se detiene en el método si colocamos un break, pero no de otra manera.

Realmente sería más util una tecla para “Avanzar StepThrough”, incluso por ahí he visto una solicitada para su inclusión en VS…pero esta es la solución parcial que tenemos disponible.

DebuggerBrowsable y DebuggerDisplay

Por defecto VS nos permite ver los miembros privados de las clases y estructuras que escribimos al momento de depurarlas. Si bien esto puede ser util, cuando la clase es un contenedor de datos, no es práctico disponer de esta información que está expuesta nuevamente en las propiedades públicas. Ni hablar si nuestra clase va a ser expuesta a terceros.

Por ejemplo si depuramos una clase “Persona” con tres propiedades vemos en la ventana de Watch una molesta duplicación de datos:

El atributo DebuggerBrowsable nos permite especificar que no se deben mostrar en el depurador los métodos, miembros o propiedades decorados con el mismo.

DebuggerDisplay, a su vez, nos permite especificar el texto a mostrar en la columna value de las ventanas de depuración. En la cadena que nos pide podemos especificar entre llaves “{}” código ejecutable, pero la mejor manera de entender esto es ver un ejemplo. Si la clase de la imagen anterior estuviera declarada de la siguiente manera:

[DebuggerDisplay("{this.GetType().ToString(),nq} ({_nombre,nq} {_apellido,nq}, {_edad} años)")]
public struct Persona {...}

(nq significa “No Quotes”, para quitar las comillas de las cadenas)

y los miembros privados estuvieran decorados así:

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Int32 _edad;

Entonces lo que veríamos en la ventana de Watch sería:

Mucho más claro si tenemos en cuenta que el tipo persona lo escribiremos una sola vez pero lo depurarán por miles de años.

Hay otros atributos de debugging que permiten desde wrappear en otra clase lo que se va a mostrar al depurar, hasta implementar un viewer customizado para un tipo, como el que Visual Studio trae para el DataSet.

Nota: No olvidar que estos atributos pertenecen al namespace System.Diagnostics, por lo que hay que agregar el correspondiente using/Imports.