sábado, 13 de septiembre de 2008

LinQ to SQL DOES have much practical use

Nowadays, big data based projects have to be accessible for multiple clients. Those clients are very prone to have much different needs on that data. So if the decision of having all the business logic required by all the clients inside the DB in stored procedures is taken, the result will be hundreds of SPs, very difficult to manage, and to create when the bussines logic comprise some complexity. In this case, just looking the "no-compilation required" advantage offered by the stored procedures is not enough. The current software industry requires connectivity in first place. Re-use and extension of basic functionality.

Stored Procedures still being a good choice though, but let them for that basic functionality you need to provide. And for clients, now there is nothing better than LinQ to SQL. Just imagine a stored procedure giving you some data you'll need to make complex calculations with, using all the power and ease offered by the .NET Framework and that you can play with all of these just using C# (goodbye to text commands!!!), everything strong typed and "intellisensed".
So I think saying "LinQ to SQL may not have much practical use", is product of a very narrow point of view. You need to have the big picture with all the new software projects style before making such asseveration.

martes, 12 de agosto de 2008

Sql Server 2008. Qué hay de nuevo?

Algo breve:

Asignación de variables en la misma línea donde se declaran
Asignación compuesta a través de operadores ( declare @n = 10 set @n += 1 'n = 11 )
Constructores de Fila mejorados (Por fin!!! - sirven por ejemplo para datos de pruebas)
Merge de Tablas (Actualiza los registros conicidentes, o agrega los nuevos)
Un tipo Tabla: Para poder ser pasado a stored procedures, etc.

martes, 22 de julio de 2008

Text Duplicates in IE6

Internet Explorer 6 has a puzzling bug involving multiple floated elements; text characters from the last of the floated elements are sometimes duplicated below the last float. This bug is a real headbanger because there seems to be nothing triggering it. However, by now everyone should know that IE needs no excuse to misbehave.

The direct cause is nothing more than ordinary HTML comments, such as, , sandwiched between floats that come in sequence. Apparently, the comments are hard for IE to digest when they occupy those positions, resulting in a kind of "screen diarrhea". HTML comments inside the floats do not cause the bug, nor do comments before or after the float series. Only comments residing between floats cause the bug.

The effect seen is that some of the last characters from the last floated element of the series are repeated outside and below that floated element. The first sandwiched comment does nothing unusual, but two comments cause the last two characters in that last float to repeat. Each additional comment makes two more characters join the party. It doesn't matter which pair of floats straddle the comments. In fact the two triggering comments may follow different floats as long as they have floats both before and after them.


From: http://www.positioniseverything.net/explorer/dup-characters.html

lunes, 23 de junio de 2008

HOWTO: Allow file downloads (including .exe) on IIS 6.0

Variations of this question are asked of IIS 6 all the time. However, the answer is no different than for any other version of IIS other than the fact that IIS 6 gives you a distinct error code to troubleshoot. What is not clear to me is why users think that the newly introduced Web Service Extension concept has something to do with this misconfiguration... I hope someone can give me some rationale.

Question:
Hello,

What is the correct method to allow .exe files to be downloaded or run from a web site on an IIS 6.0 server?

I am currently receiving a 404.2 error message in my browser when I try to open/download the executable files, and I am not sure which Web Service Extensions configuration changes must be made to allow this.

Thanks in advance,

Answer:
Given the current phrasing of your question, there is no correct method. Downloading a .exe file is NOT the same as run from a website, as I will describe below. I'll give a short answer and then a more detailed answer.

Short Answer
Your error message indicates that you have "Scripts and Executables" enabled, so IIS is trying to execute the .exe file on the web server, and since the .exe is not allowed by any defined Web Service Extension, a 404.2 results. The corrective action depends on what you want to do.

If you want to allow .exe files to be downloaded as-is to the browser, then you must NOT have "Scripts and Executables" as Execute Permissions.
If you want to execute the .exe file on the server to generate a response that is sent to the browser (possibly interpreted as a download), then you MUST have "Scripts and Executables" as Execute Permissions, and you must enable a Web Service Extension for that .exe file.
Details
Whenever the user makes the browser request a resource like "http://server/myapp.exe", users usually want one of the following actions to happen:

Return the file contents of myapp.exe as-is to the browser (aka file download)
Execute myapp.exe on the web server to generate a dynamic response (aka execute CGI script)
Now, the web server controls which action should happen, and on IIS, this is controlled by the "Execute Permissions" property of the virtual directory containing the .exe file. If the permission is set to "Scripts and Executables", then IIS will do action #2. Otherwise, it will do action #1.

Prior to IIS 6.0, there were no further security checks against either action. On IIS 6.0, there is one additional security check, depending on the action:

For action #1, the file resource's extension (.exe in this case) must have a defined MIME Type or else a 404.3 occurs. .exe has a MIME Type of application/octet-stream by default, so file download should just work.
For action #2, there must be an enabled Web Service Extension for the full path to the .exe resource to allow IIS to execute it to generate a HTTP response or else a 404.2 occurs. For securety reasons, IIS 6 does not allow any resource to execute by default unless otherwise configured/allowed in Web Service Extension.



From: http://blogs.msdn.com/david.wang/archive/2005/07/11/Allow_file_downloads_on_IIS_6.aspx

jueves, 19 de junio de 2008

Detallitos de CSS en Themes de ASP.NET

Los descubrimientos descritos a continuación, surgieron de mi necesidad de cargar CSS dinámicamente si estar creando mumerosos temas dentro de una aplicación WEB ASP.NET.

En primera instancia: Toda página que referencie un tema, SIEMPRE cargará absolutamente todos los CSS incluidos en el mismo, independientemente de que en realidad los necesite, y del nivel de anidamiento en el que se encuentren ubicados. Poco eficiente no es así?

Como se sabe, los CSS finalmente son Links referenciados en el HEAD de la página que está referenciándolos. Entonces es cuestión de escribir dinámicamente allí la ruta del CSS que se desea cargar y listo.

Lo anterior se logra metiendo un ASP.NET literal control dentro del HEAD, y en el load de la página ajustarlo con el valor que se desea.

Y listo!!!
Verificando con Firebug, se observa que a pesar de que existan varios CSS en la misma ruta de aquel que está siendo referenciado, solo el referenciado se descarga.

Ventajas?
Tener organizados varios CSS y no solo uno gigantesco con todo.
En cuanto a ancho de banda, si los CSS se dejan dentro de temas, por más separados que estén si son cargados por medio de referencia al tema desde la página, siempre bajan todos la primera vez que se llamen (luego quedan en el caché y no vuelven a descargarse si no se borra el caché o si no cambian en el server).

Si se desea optimizar el tiempo de descarga, entonces es mejor no usar Themes para cargar los estilos, sino que estos se carguen independientemente usando el modelo de HEAD descrito anteriormente.

lunes, 7 de abril de 2008

Table vs. DIV

I have a little story to tell about the webmaster who used a table with DIVs and the webmaster who didn't. The webmaster who didn't use a table had the higher paying job, a big house, a nice car, and a hot wife because he got all the good jobs for his tableless designs. The webmaster who used tables only to insert his DIVs was considered a second-rate bum and many believed he didn't even know how to position his DIVs. He made very little money. He lived in a rundown apartment. He had no car, and he had no wife.Then oneday the webmaster who had a classy job and the ever-so-popular tableless designs one day was sitting at his desk smoking a cigar talking on his cell phone about where to meet his buddies for lunch when his boss came running in all excited and out of breath."We just got a whole bunch of affiliate partners that want to place ads on our pages so they can make money and we can make commissions! We want an entire column added to the right side of every page!"Now the site had been around for several years and there were thousands of pages of content to add this column to, and the pages were all written in DIVs. So, the webmaster gasped and dropped his phone as the cigar fell from his mouth and he said, "Well, that is going to take some time, I got to place new DIV tags on every page to add one column of ads and that is no easy task!"The boss lamented this news, because not only would that mean he would not be making money off of his affiliates until the job was done, but he would have to hire someone else to assist the webmaster with his work until the site was updated. So, trying to save some money and not wanting to take a lot of time to hire someone on a contract, he hired the poor unsuccessful webmaster who always used tables to position his DIVs. The poor and destitude webmaster reluctantly decided he had no choice but to accept the tedious task, because he needed the money. So, for nearly a month he labored on inserting the appropriate DIVs on each page, copying and pasting many times into each page. When it was all said and done he went to the boss, and he shook his head and said, "You know it took a lot of copying and pasting to insert all them new DIV tags...If the site had been designed with a table I would have only had to copy and paste once into each page to insert the new column. You would have made a lot more money instead of having to hire someone else on, and it would have saved me from a lot of headaches going vertigo looking at code. I hope you never have to add a column again, for your sake and mine."The boss shook his head, and stopped the man before he could go. "Wait!" he said. "I could have been making tens of thousands of dollars a day all this time if you had done my site with tables?"The tired and frustrated impoverished webmaster nodded with a grim expression, and the boss threw up his hands and rolled his eyes. Racing out of his office, he motioned for the poor webmaster to follow after him as he charged into the rich webmaster's office. The rich webmaster was polishing his W3C Validation pin on his suit jacket as they entered and he smiled saying, "So, did the columns get added to all the pages?""Yes!" shouted the boss, "but you're fired! I got me a new webmaster right here who is going to make sure I never lose money adding a column of ads again!"Now, the poor webmaster is no longer poor, and the rich webmaster is no longer rich. He lost his big house. He lost his nice car. He lost his hot wife, because she only loved him for his money, and he is in the psyche ward for going nuts and breaking computers at a department store.

Like it is said: It all depends on the viewpoint. It exists another technique yet. The CSS positioning. It have its advantages and drawbacks too. So please try using all of this techiniques and acquire the experience. Then you will know which technique will be the best choice.

miércoles, 26 de marzo de 2008

Asignación dinámica de eventos a controles pertenecientes a controles compuestos.

Una dificultad que se tiene con controles compuestos cuando estos hacen parte de una colección dinámica, es asignarles eventos a los controles que los componen, ya que no se sabe de antemano cuántos van a ser.
Generalmente estos controles integrar un Repeater, que repite el control, por cada elemento dentro del DataBind de dicho Repeater.
Entonces basta con capturar el evento ItemCreated del Repeater. Cuando suceda, se busca el control compuesto y sus componentes. Y es en ese momento cuando ha de asignársele el evento a los sub controles que se deseen.

Generic Handlers

Un Generic Handler (GH) es otra clase de objeto que puede procesar http requests, sin necesidad de estar dentro del scope de una página (que está dirigida a presentar salidas de tipo HTML clásico). Un ejemplo de GH es el HTTP Handler. Como es bien sabido un http Handler se puede asociar a cualquier extensión de archivo (de acuerdo a lo permitido por el IIS). Los GH sin embargo, solo se pueden asociar a la extensión ASHX que está directamente soportada por los proyectos web en visual Studio 2005 y posteriores. Todos los Handlers implementan System.Web.IHttpHandler. Además, en IIS 7 se puede alojar cualquier Handler directamente.
El hecho que el GH pueda correr fuera del entorno de una página y aparte procesar HTTPRequests, lo hace una herramienta perfecta para ofrecer servicios de este tipo a otras aplicaciones, cuando no se han implementado como WebServices ya sea por requerimientos del negocio o requerimientos no funcionales.

Por qué puede no ser deseado un WebService?

Según la arquitectura y requerimientos de algunos clientes, es mejor recibir resultados a través de HTTPRequest "pelado", debido a que por ejemplo el llamado se hace desde una plataforma distinta a .NET desde la cual se hace bastante complejo crear un llamado a un WebService, tal vez porque la herramienta no puede manejar todos los tipos estándar en los WebServices (como sucede por ejemplo con PHP).

Entonces por qué no hacer una página Web Normal que responda a los llamados?

Si se crea una página aspx que responde a las peticiones se incurre en adicionales encabezados y todo el overhead adicional que genera la creación de una página completa (viewstate, etc), cuando en realidad solo se desea obtener una simple respuesta (una imágen un xml, etc).

Entonces para ganar performance y facilidad de administración en este tipo de funciones, es posible crear un Generic Handler sin dejar de atender al requerimiento de que la comunicación permanezca sencilla.

Entre los métodos obligatorios al estarse implementando IHttpHandler está ProcessRequest que es el que ejecuta el proceso requerido y por ende al fnal de su alcance habrá de tener un llamado a context.Response.Write o similar, que devuelva una respuesta http. Esta respuesta puede ser html, txt plano, imágenes, xml, etc.

Otra utilidad muy práctica es la de presentar objetos de memoria (entidades) en páginas WEB. La idea es tomar un objeto (serializable) en memoria que tenga representación XML. Se toma esta representación XML y se pasa por una transformación XSLT, produciéndose un HTML que representa a dicho objeto. Una de las aproximaciones para mostrar este HTML es grabarlo en un archivo y luego en otra página con un IFrame cargar dicho archivo. Pero como es obvio, el overhead de crear y borrar estos archivos físicos generados es absolutamente inaceptable. Otro enfoque es incluir en la página un control XML que muestre el objeto serializado y en el cual luego de hacer la transformación se vea el HTML como tal. Es una alternativa muy aceptable que a primera vista no tiene ninguna desventaja. Pero usando GH, se obtiene una control más directo sin el overhead que implica agregar un control XML a una página que además tendrá otros elementos que sumaran innecesariamente peso al resultado. Al crear un GH que tenga un tipo de respuesta XML, éste puede ser llamado (los GH se llaman como cualquier otra página aspx. Además también pueden aceptar parámetros: http://warnov.8m.com/miGH.ashx?param=valor;otroparam=otrovalor)a través de la su URL y el retorno obviamente será el HTML que representa al objeto deseado (siempre y cuando el XML incluya la directiva de transformación XSLT y el archivo XSLT se encuentre en la ruta que allí se especifica).
Como se observa, son muchas la aplicaciones que tienen estos objetos y es considerable la ganancia que se obtiene con su uso.

lunes, 18 de febrero de 2008

MediaMonkey extendido con C#


Es un opensource project que creé y subi a Google code, para probar. Aquí está el link https://mediamonkey-cs-tagger.googlecode.com/

Resultados de división en SQL: No se traen decimales por defecto?

Sujeto A: oiga una pregunta estupida de SQL
WarNov: a ver
Sujeto A:
DECLARE @Variable Float
SET @Variable = 170/100
SELECT @Variable

porque no me muestra decimaleS??
Sujeto A: alo??

WarNov: Hágala entonces más breve:
DECLARE @Variable FloatSET @Variable = 170.0/100.0
SELECT @Variable

Sujeto A: chambon
WarNov: CHAMBON SU * ahí no tiene nada de chambón
si ud no puede controlar los valores, entonces use:

DECLARE @Variable Float
SET @Variable = cast(170 as float)/cast(100 as float)
SELECT @Variable

contenta?

miércoles, 13 de febrero de 2008

Closures? Kejeso?

Tomar el framework 2.0, usar sus delegados y métodos anónimos, generar un productor de delegados con un parámetro de configuración y se obtendrá un closure.

Pero... what for?

Ha tenido por ejemplo que calcular un impuesto como el IVA que puede variar según el artículo?
Por ejemplo para una crema dental es de 16% pero para un auto es mayor al 20%. Let's say 25% para el ejemplo.

Entonces el programador bien juicioso se hace el siguiente método:

decimal IvaCalc(decimal tax, decimal amount);

Así pues siempre que uno vaya a llamar al método tiene pasar ambos parámetros:

decimal imp1 = IvaCalc(25d, 25800d);
decimal imp1 = IvaCalc(16d, 4d);
decimal imp1 = IvaCalc(16d, 5800d);

etcétera

Entonces se puede optar por hacer dos métodos... uno por cada tipo de IVA.
Pero si son 10 tipos de IVA hará 10 métodos?

Entonces opta por hacer un objetico calculador de IVA:

public class IvaCalculator
{
decimal _tax;

public IvaCalculator(decimal tax)
{
_tax=tax;
}

public decimal calc(decimal amount)
{
return _tax*amount/100d
}
}


De esta manera basta con instanciar un objeto por cada tipo de IVA y ponerlo a trabajar; esto minimiza la cantidad de código escrita, y es bastante claro:

IvaCalculator autoCalc=new IvaCalculator(25d);
IvaCalculator prodCalc=new IvaCalculator(16d);
decimal imp1 = autoCalc(25800d);
decimal imp1 = prodCalc(4d);
decimal imp1 = prodCalc(5800d);


Pero de nuevo... si son diez tipos distintos de IVA, creará diez instancias de objeto? Es justo tanto empleo de memoria al tener un objeto completo solo para hacer una operación?
No lo creo... precísamente para solventar esta situación son útiles los enclosures.(Entre otras)

Un enclosure permite reflejar la simple funcionalidad de la pequeña clase que diseñamos anteriormente, sin incurrir en el overhead del objeto como tal. Para lograrlo, se requiere una forma de mantener un estado (en este caso, la tasa del impuesto) para no tener que estar pasando el parámetro de configuración en cada llamado. Además se requiere una operación sobre ese estado. Cómo lograrlo sin tener que hacer un objeto?

La operación como tal, se logra con un simple método. Pero este método debe ser configurable en su creación de manera que tenga un estado.

Para que se pueda configurar es necesario que exista una variable en un ambiente léxico (scope) superior al del método, de manera que esta variable pueda ser inicializada sin necesidad de llamar al método. Esta, será pues la variable que indica el "estado" del método:

class....
{
decimal _tax;
public decimal IvaCalc()
{
....
}
}

Pero igual, eso está dentro de una clase. De hecho en C# todo lo que ejecute, ha de estar dentro de una clase. La ventaja ahora, es que vamos a trabajar dentro de la misma clase de ejecución de nuestro flujo. No tendremos que crear más instancias. Así que continuando:

Tanto el parámetro como la operación deben quedar encapsulados dentro de un mismo ambiente léxico dentro de la clase, para que tengamos la unidad requerida para poder generar instancias (pero no de una clase que es lo que queremos instanciar, sino de algo más light que llamaremos "enclosure"). Para esto es necesario poder hacer referencia al método dado.

Qué nos permite hacer referencia a métodos? Si... correcto: los delegados. Entonces generamos un ambiente léxico que tenga al delegado referenciando al método y al parámetro de configuración. Obviamente si estamos dentro de una clase y no queremos generar otra, ese ambiente léxico es un nuevo método. Este método deberá retornar el delegado apuntando a la operación ya configurada como es debido, pero además el método al que apunte el delegado deberá estar declarado inmediatamente, de manera que el parámetro de configuración del mismo sea accesible a éste, desde el método que lo contiene.

En teoría suena bien. Pero cómo lograr que un delegado apunte a un método que se declara "en línea" junto con éste?

Ahí es donde entran los métodos anónimos. Son precisamente eso: Métodos declarados en línea donde son requeridos por los delegados. Generalmente, los delegados se han inicializado con el nombre de un método que cumpla el contrato de su firma. Ahora (Framework 2.0 en adelante), no es necesario declarar el método aparte para poderlo referenciar luego por un delegado (lo que impediría acceder al dichoso parámetro de configuración) sino en línea junto con la declaración del delegado:

delegate int MyDelegate(int a, int b);
MyDelegate myDel = delegate (int a, int b)
{
.....
return ....
};

No olvide el ";".

Ya con este conocimiento, podemos generar el método que queremos:

delegate decimal ivaCalc_(decimal amount);
ivaCalc_ ivaCalcProducer(decimal tax)
{
return delegate(decimal amount)

{
return amount*tax;
};
}


Exótico no?

Pero a pesar de ello, logramos lo deseado: El método toma una variable de configuración. Así tenemos estado y manipulación de estado. Lo que haría una clase. Entonces ahora como se operaría es muy parecido al uso de clases anterior; solo que ahora no hay overhead por creación de nuevos objetos. Lo que se crean son nuevos delegados. Uno por cada tipo de tasa en este caso. Ellos "comen" mucho menos que un objeto:

IvaCalc_ ivaCalc16=ivaCalcProducer(16d);
IvaCalc_ ivaCalc25=ivaCalcProducer(20d);
decimal imp1 = ivaCalc25(25800d);
decimal imp1 = ivaCalc16(4d);
decimal imp1 = ivaCalc16(5800d);

Y listo... gracias a lo anterior por fin le ví un uso práctico a toda esa parafernalia mística de métodos anónimos que vino con el framework 2.0. Aunque sé que otra gran utilidad es en las expresiones lambda que trataré de abordar en otro post, pero pues, primero el 1 y luego el 2.

viernes, 8 de febrero de 2008

Snack Overflow Exception

Digo, Stack...

El error, StackOverFlowException.
Más de una semana sin solución. Buscaron en internet a ver... nada.
Los StackOverFlow Exception no se pueden capturar con un try catch. Ni lo intenten. Cuando sucede la aplicación está más muerta que al cerrarla.
Finalmente, me preguntaron....
"Eso es que tienen una función recursiva con el punto de parada mal diseñado" les dije.
Pero no había tal.
Entonces me puse a mirar...
en la primera ocasión no vi nada anormal en realidad. Solo un par de cosas para optimizar el código. Pero nada como para decir que el misterioso snack dejara de aparecer.
Una y otra vez se repetía. Y lo peor, es que era un proceso bastante largo, que siempre fallaba luego de la primera horta. Así que hacer debug era un infierno total.
En la segunda ocasión que me senté a mirarle el código, tampoco vi nada raro; se me ocurrió que depronto había mucha memoria desperdiciada... pero nótenlo: eso nunca tiene que ver con el stack. Snack es una cosa y Stack es otra y Memoria no tiene que ver con ellos. El Stack almacena el listado de funciones que se han ejecutado. Y tiene un tamaño entre 500 y 1000. Así que si llamamos más de ese número, el stack secillamente se llena y la aplicación colapsa.

Teniendo esto muy presente, decidí volver a chequear el código una tercera vez...
y oh sorpresa cuando al fin encontré lo que estaba pasando!!!!

Había un método que al final del mismo, tenía un disparador de evento. Otra clase capturaba ese evento y en respuesta lanzaba la ejecución de otro proceso distinto que antes de terminar volvía a lanzar ese evento y así sucesivamente. Todo esto siempre se ejecutaba con el mismo thread. Así que cada vez, el método se quedaba esperando a que se ejecutara el siguiente. Por esto el stack comenzaba a llenarse hasta colapsar, porque las funciones no terminaban, pero si se llamaba a otras.

Es algo para nada obvio. Pero al fin por pura intuición se descubrió. Lo ridículo del asunto, era el mensaje que representaba el evento disparado: "Terminé" Entonces otra clase leía que había terminado y ponía a correr otro proceso. Que sentido tiene eso? Era muy difícil programar a la clase externa que corriera un proceso y luego otro y otro y ya? No lo creo. Sencillamente a algunos diseños les falta ingeniería de verdad.

jueves, 7 de febrero de 2008

The Literal Control Spirit

This simple but powerful control, sometimes generates false expectatives, around itself. I've seen in some forums, people using'em instead the Labels, cause "Performance Issues". But; nevertheless the Literal is simpler than the Label control, the performance enhacements got with the former control is not very significative.

Then, which is the power of the Literal Control? The importance of Literal, beyond performance, is that you can write html formatted text (i.e. A paragraph with
and stuff like this... have u tried to make a line change in a label containing lots of text and needing to be formatted -making bold some words in instace?) in a more controllable way than using Response.Write as an example.


Thus, you put the literal control wherever you want and control some behavior over it (Like it's content, if it is visible or not, etc).Sadly, style sheet controlling is not available for this control (There is a lack of the property CssStyle which is present in most of common controls as labels).

But is logic u need to keep the consistence of your web site and don't create a font mixing which will be worst for the user feelling who will prefer read your page written by pencil. A simple way to do this, is make the Literal be part of a Panel. The panel will acept the css property and the Literal, will inherit this appearence.

Transmitiendo Variables de Aplicación entre Capas

(Y haciéndolas dinámicas)

Sea el escenario de una típica aplicación 3-tier para un sistema de información. Hay una capa de presentación, una de negocios y la de datos. En la capa de datos según lineamientos plenamente aceptados, tenemos las cadenas de conexión a las bases de datos que se usarán. Si la aplicación se desarrolla con el framework 2.0, es normal que las capas de datos y negocio, queden representadas por DLLs que luego son consumidas por una aplicación windows o web, por ejemplo. Entonces cada cliente se comunica con sus capas servidoras que tienen la conexión a base de datos y saben en dónde están los datos para operar.

Hasta ahí no hay ningún problema. Cuando la aplicación ya está lista para producción, generalmente se usará una base de datos distinta a la usada en desarrollo y quizá en pruebas.
Este cambio, gracias a la arquitectura del framework 2.0, solo implicaría cambiar el archivo de configuración (App.config) de la DLL de capa de datos. Se abre con un editor de texto, y se edita el XML con la nueva cadena de conexión, y ya está. Todos los clientes quedan conectados a la nueva fuente. Pero qué sucede si se crea una aplicación de capas, que no necesariamente tiene la misma conexión de base de datos para todos los clientes? Cómo lograr que cada cliente genere una cadena de conexión dinámica que se pueda cambiar a discreción permitiendo que la aplicación funcione correctamente?

En el framework 2.0 las cadenas de conexión son tratadas como variables de alcance de aplicación. El otro tipo de alcance es de usuario. Cuando la variable es de alcance de usuario, esa misma, puede ser modificada en tiempo de ejecución. Entonces sería fácil crear métodos para que los clientes de presentación de alguna manera transmitieran los nuevos valores de las cadenas de conexión a las otras capas. No obstante, como mencioné anteriormente, las cadenas de conexión son de alcance "aplicación" y estas variables no se pueden modificar en tiempo de ejecución. Así que para un cliente es imposible modificarlas transmitiendo nuevos valores mientras está corriendo. Así que el método de crear código que transmita los cambios requeridos, no es factible. La solución, aunque es trivial, no es intuitiva y Visual Studio no provee una manera directa para lograrla. Para encontrarla y entender de qué se trata, suponga que llamamos a la cadena de conexión strCon1. Entonces, queda guardada dentro de los settings de la DLL de datos como strCon1 y tiene determinados valores de conexión.

Además permitiría cambiar la cadena de conexión dinámicamente, antes de iniciar la ejecución de la aplicación (recordemos que ésta es una variable de aplicación). Al distribuir la aplicación, se puede hacer con o sin el archivo de configuración de la aplicación. Si se distribuye sin este, cuál será entonces la cadena de conexióna usarse? Se usaría la última presente al compilar la librería (Esto gracias a la compilación del archivo de propiedades en la clase Settings.settings).

Como es conocido, cada capa en el framework, vendría representada por un assembly (dll) por separado. Es decir, cada capa es un proyecto dentro de la solución y cada proyecto de estos, tiene sus propias propiedades y variables de usuario y aplicación. Como ya se mencionó estas variables van en archivos App.config. Al compilar la solución, dentro de cada carpeta de salida de los proyectos queda un archivo App.config para las dlls, y un archivo miaplicacion.exe.config para los ejecutables en el caso de aplicaciones windows o web.config en el caso de web services o aplicaciones web ( en estos ultimos dos casos, el archivo queda en el root del sitio web).

Lo que uno como desarrollador distribuiría, sería únicamente los compilados y salidas de los proyectos componentes de la solución. Entonces irían en nuestro ejemplo dos dll (una de datos, la otra de negocio) y el ejecutable. Además irían los archivos de configuración, que en el caso de las dll se llamarían igual.

Pero si se llaman igual, cómo se soluciona este problema? Fácil; basta con combinar los archivos de configuración en uno solo con el mismo nombre y listo. Pero es fundamental que los nombres de las variables (por ejemplo de cadenas de conexión) permanezcan invariables.

En mi búsqueda de esta solución, una de las cosas que intenté fue agregar una variable de aplicación a la capa de presentación, que tuviera el mismo nombre de conexión y los mismos parámetros que la definida en la capa de datos usando la interfaz de Visual Studio. De esta manera se produciría un miaplicacion.exe.config, con la cadena de conexión que usa la capa de datos y así cada vez que yo cambiase este archivo y reiniciase la aplicación, el sistema tomaría los cambios y funcionaría de acuerdo a ellos.
Al ver con más detalle el resultado, descubrí que el nombre de la variable no había quedado exactamente igual que el usado por la capa de datos. Y en la práctica, este hecho no es muy fácil de identificar.

Así que dado que uno puede estar tentado a agregar el setting usando la interfaz de Visual Studio, puede incurrir en este error si no se fija lo suficientemente bien. Lo mejor, es no agregar el setting de esta manera. Sino agregar a mano (o editar a mano si ya existe), un archivo App.config y escribir el setting exactamente como se usó en la capa de datos.Cuando así lo hice, con felicidad observé como finalmente los cambios en el archivo XML se veían reflejados en la aplicación, cuando esta empezaba a correr. Esto me dió la felxibilidad requerida para configurar cada cliente con una fuente de datos distinta a la usada en el desarrollo de la aplicación.

Conclusión: Para propagar las variables de configuración desde las capas más exteriores a las más interiores dentro de un sistema n-tier usando framework 2.0, basta con escribirlas todas en el archivo de configuración de la capa más externa, de manera que sean absolutamente idénticas a las usadas en las capas internas. Y no es posible hacer esto, solo con la ayuda de la interfaz gráfica de Visual Studio 2005, pues se requiere editar el archivo manualmente y luego incluirlo en el deployment de la aplicación.

No agregue tablas con el mismo nombre

QUÉ SUCEDE AL AGREGAR UNA TABLA A UN DATASET QUE CONTIENE YA UNA TABLA CON EL MISMO NOMBRE?

Esta duda se me originó cuando en una aplicación Web, desde las capas superiores le enviaban a la de presentación un DataSet con datos de tablas referenciales (es decir, aquellas que no sufrían mucho cambio); dada su naturaleza decidí poner este dataset en el singleton de la aplicación. Pero sucede que luego decidieron que las tablas de referencia en realidad iban a cambiar de cuando en vez. Así que había que proveer un mecanismo para informar al singleton que su dataset había cambiado y se debería recargar una(s) de sus tablas. No obstante dada la separación de capas y que no existe en la capa de presentación acceso a los TableAdapters, la única solución fue bajar de nuevo la tabla ya actualizada.
Para esto recurrí primero a dataSet.Tables["nombre"]=servicio.GetTable["nombre"];pero es erróneo porque dataSet.Tables["nombre"] es de solo lectura y no se puede cambiar.
Así que luego ví:dataSet.Tables.Add(table);
pero como se supone que la tabla ya existe, no sabía que consecuencias implicaría hacer esto. Busqué en la yuda y no encontré nada fácilmente. Así que decidí que sería más rápido investigar por mi propia cuenta.Lo que sucede es que al intentar agregar una tabla con el nombre de una que ya existe, se produce una excepción que arroja más o menos ese mismo mensaje. Así que no es que se produzca un "merge" de los datos, ni que halla un reemplazo del obketo tabla como tal. Sencillamente, no se puede.
La solución, bastante sencilla: Si existe un Add, obviamente ha de existir un Remove. De esta manera, usando el Remove anteriormente al Add, para la misma tabla se obtiene el reemplazo con los datos actualizados.
Sin embargo, el problema que originó buscar esta solución, obviamente está basado en un sitio Web mal concebido desde sus principios, pues esta última solución no es la mejor, pues lo ideal, sería que el cambio se hiciera en la capa local y luego en la capa superior, o que solo se trajeran los registros actualizados de la capa superior, y no de nuevo toda la tabla.
Pero por premuras de tiempo y errores sucesivos en el diseño, me vi forzado a buscar esta solución no muy grata. Espero poder convencer de usar lo último que en realidad sería más rápido que volver a traer todos los datos.

lunes, 4 de febrero de 2008

Don JSon

Algunas aplicaciones web requieren AJAX y requieren que su tamaño de página ha de mantenerse bajo límites estrictos. Entonces no es posible usar las librerías de AJAX .NET dado el considerable peso que le agregan a la página, sino usar directamente el objeto XmlHTTPRequest. Adicionalmente es necesario considerar el peso impuesto por los datos que se transfieren desde el server al cliente luego de usar AJAX. En primera instancia uno podría pensar en XML. Pero como se sabe, los archivos se hacen muy grandes con información que finalmente no es la relevante, así que se genera más peso para las páginas. Por este motivo, actualmente se está difundiendo rápidamente el uso de JSON.

JSON es un sobconjunto del lenguaje JavaScript, que permite representar objetos a través del paradigma llave-valor. En síntesis es como un "fatless" XML, que es mucho más liviano. Y que además tiene la gran ventaja que puede ser interpretado directamente por JavaScript, de manera que tanto el peso de la página como la ejecución se mejorar sustancialmente, ya que no hay que usar librerías para manejo de XML en JavaScript ni hacer tediosos recorridos a través del texto.

Para JSON hay librerías disponibles en casi todos los lenguajes, incluido C#. De esta manera, cualquier objeto puede ser traducido a de C# a texto JSON en el server, luego transferido al cliente usando Request.Write después de un llamado AJAX, e interpretado inmediatamente por el browser, sin mayor overhead.

En C# 3.0 (disponible en VS2008) muchas de estas características están siendo implementadas de forma nativa y ofrecen beneficios incalculables a la hora de desarrollar, por lo que es recomendable desde ya comenzar a usar estos elementos que han existido desde hace mucho tiempo, pero que solo ahora con el auge de “la interpretación – AJAX, Silverlight, etc- han entrado de lleno en el mundo Microsoft.


El sitio oficial es
http://www.json.org
Pero para no devanarse los sesos y entender rapidito el asunto está: http://www.secretgeek.net/json_3mins.asp; en tres minutos sabrán qué es.

El web service se reventó.

O no supimos configurar el HttpRuntime
O lo encargamos de lo que no era

El webservice protagonista de este post fue creado y usado para lo que no debería ser. Exponía una funcionalidad de una aplicación web administradora de contenidos. Como esa era muy compleja "pa meterle la mano" entonces la dejaron intacta, solo que le "samparon" el web service, para que la aplicación propia pudiese usar el dichoso administrador de contenidos.

En teoría funcionaba bien. Pero ante cargas significativas: "The thread have been aborted". Y nadie sabía qué era. Mejor dicho, se "totiaba". Entonces me llamaron a ver que era. Y lo primero que observé, es que el pobre webservice exponía unas operaciones que operaban sobre la base de datos. Y en general eran operaciones costosas. Pero lo peor, es que siempre el webservice tenía que quedarse esperando la respuesta del servidor de DB.

"Eso es el timeout del webservice" dije.
"Si, pero ya le pusimos hasta 5000 horas y nada!!"
Ouch!!!

Entonces tratemos de optimizar las operaciones de la DB.
Le pasé el profiler, el DBEngine Tunning Advisor, implementé y borré índices y en efecto. La vaina mejoró.
Operaciones de 9 minutos pasaron a 3 y en otros casos operaciones de 3 min pasaron a 1 seg (y eso porque el reporte no mostraba menos de 1 seg)

Pero llegamos al punto en que por más optimización que hicimos, el error seguía pasando y el thread seguía siendo abortado.

Cuál thread? Pues el del webservice. Entonces insistí: "Eso tiene que ser algún timeout"
El sujeto directamente implicado entonces muy juicioso esa noche googleó y googleó hasta encontrar un nuevo parámetro de timeout. Y tome!!! "Le pegó al perrito" (Lamento no haber sido yo, así la recompensa para mí hubiese sido mayor. Pero me agrada haberlo guiado por el camino de la luz... veo una luz veo una luz!!!)

El httpruntime es un parámetro de configuración en el webconfig y jugar con sus valores puede ser catastrófico o genial. (En este punto cuando he nombreado web.config obvio que sabrán que estoy hablando de asp.net. especficamente del 2.0).

Señores, se los presento aquí.

Allí encontramos como atributo a executionTimeOut y fue el que le pusieron como en 5000 y nada. Por qué?
Uno diría que aquí es donde le puede decir al webservice que espere más antes de "morirse". En efecto así es. Lo que pasa es que con el framework 2.0 vino nuevo otro atributo: shutdownTimeout. El primer atributo aplica sobre la aplicación como tal. Pero el segundo aplica sobre el worker process. Así que si está muy bajo para lo que uno quiere, el worker process es "bajado" por ASP.net cuando el tiempo expira y adivinen que pasa "The thread has been aborted".

Lo pusieron en 1000 y por fin pudieron hacer su prueba completa!!!

Concluyendo: Para evitarse problemas, no ponga a los webservices a esperar respuestas a trabajos completos. Esto margina el rendimiento de la red, y en general de todos los recursos del sistema. Eso mándelos a ejecutar algo y que se desprendan de una. Y luego ponga un observer a que mire si el otro ya acabó el trabajo. O quizá mantenga otro tipo de suscripción.

Si ya la embarró y no hay tiempo para cambios o definitivamente la terquedad o condiciones del negocio no permiten más, acuda al httpruntime y sus dos timeouts; esto puede apagar el incendio.

viernes, 1 de febrero de 2008

La piscina de Sql Connections

Cuando se crea una conexión SQL en ASP.NET, por defecto siempre irá al POOL de conexiones administrado por el framework. Es así como ni al cerrarla ni haciéndole dispose, esa conexión realmente se cierra en el SQL Server como tal. El pool de conexiones existe para mejorar en general el rendimiento de las aplicaciones, dado que el hecho de abrir una conexión es bastante costoso. Así que aunque lógicamente la conexión está ConnectionString es requerida, se sirve una de las ya existentes en el pool de una manera más rápida que creandola desde 0 (from the scratch).

Si no se desea este comportamiento, basta con incluir en la conexión o en el WebConfig POOLING=FALSE

El pool para un ConnectionString en particular se puede configurar con el número máximo y mínimo de conexiones. Jugar con estos valores puede mejorar o empeorar el rendimiento de la aplicación. El valor por defecto es de 100.

Existe un error bastante grotesco que puede asustar mucho si no se entiende de connection pools:

A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

Ocurre por ejemplo si en el pool no hay conexiones disponibles, debido a que han sido terminadas por un ente distinto a la aplicación (alquien desconectó el cable de red, apagaron el server, le hicieron kill a las conexiones, etc.)

No ocurre porque la operación esté tardando demasiado. Y el que ocurran excepciones por éste último motivo no se arregla aumentando el timeout de la conexión. El timeout de la conexión se refiere al tiempo de espera para logran conexión con el server de db, antes de que una excepción sea lanzada.

El tiempo de timeout por defecto es de 15 segundos. Y en el connectionstring está medido siempre en segundos. Siempre ha tener valores positivos o 0. De lo contrario una excepción surge. Si es 0, significa que nunca se lanzará excepción por incapacidad de alcanzar al server. Esto no es buena idea, porque el sistema se puede volver irresponsivo, y no habría indicios de por qué sucede esto.

Lo que viene es tomado de http://www.ondotnet.com/pub/a/dotnet/2004/02/09/connpool.html

My final thought, expressed in code (of course), is a handy method that will return the value of any connection string parameter passed into it. I'll leave it to you to improve the DAC with it:

private string GetParameterValue(string conStr, string searchParam)
{
// searchParam, e.g., "Max Pool Size" or "Incr Pool Size"
int posBegin = 0;
int posEnd = 0;
char[] delimiter = {';'};
string paramVal = string.Empty;

posBegin = conStr.IndexOf(searchParam);
if (posBegin > -1)
{
// add one for '=' char
posBegin += searchParam.Length + 1;
if (conStr.LastIndexOfAny(delimiter) > posBegin)
// somewhere in the middle
posEnd = conStr.IndexOf(';', posBegin);
else
// at end of string
posEnd = conStr.Length;
paramVal = conStr.Substring(posBegin, (posEnd - posBegin));
}
return paramVal;
}

Para que los pool funcionen correctamente, debe existir un manejo responsable de las conexiones. Cómo se manejan responsablemente? Cerrándolas cada vez que no se vayan a requerir más.

SqlConnection conn = new SqlConnection(myConnectionString);
try
{
conn.Open();
doSomething(conn);
}
finally
{
conn.Close();
}


Como se vé si hay un fallo, igual se cierra la conexión.

Teniendo en cuenta: http://www.15seconds.com/issue/040830.htm

"Close and Dispose methods of Connection object are equivalent. Neither one gives you any specific advantages over the other. "

Por tanto se puede usar también de una forma más elegante y ostentosa:

using (SqlConnection conn = new SqlConnection(myConnectionString))
{
conn.Open();
doSomething(conn);
}


El using en exte contexto libera todos recursos declarados, por medio de Dispose.