Mi amigo Natacuin, gran programador aunque últimamente más del lado de la administración, planteo hace poco esa pregunta: se debe utilizar un único webservices con muchos webmethods o es preferible por rendimiento partirlos en varios webservices con menos webmethods.
El mismo Natacuin buscó su respuesta planteándose un escenario y una serie de pruebas reseñables las cuales se encuentran en esta entrada de su blog para consulta y mayor detalle.
La conclusión a la que llegó es que "Las diferencias existen pero no son abismales, lo que significa que para que el rendimiento sea un factor a tomar en cuenta, los request por segundo al sistema deben ser miles ". Y que la recomendación es que es preferible usar múltiples webservices, lo cual también puede redundar en otros beneficios como en un mayor orden ya que se pueden agrupar en un webservice los webmethod afines, logrando asu vez facilidad de mantenimiento e incluso de programación por cuanto se pueden atender varios webmethods por varias personas sin pensar en la consistencia del código en el caso de que no se contase con una herramienta que lo controle por nosotros.
11 jul 2009
OLEDB para cargar archivos de excel
Recientemente debíamos cargar un archivo al servidor y cargar sus celdas en una base de datos. Ademas debíamos cumplir el requerimiento de no instalar ningún componente de MS Office en los servidores.
Como sugerencia del departamento de sistemas del cliente se nos indicó que utilizáramos Dtsx para realizar esa operación y de hecho llegamos un solución con paquetes SSIS. Sin embargo se nos complicó por una cuestión de permisos. Finalmente optamos por hacer una solución basada en OleDB más sencilla y más fácil para darle mantenimiento.
¿Y el rendimiento? pues ninguna diferencia porque resulta que los Dtsx para manejar excel utiliza OleDb. He aquí parte de la solución con .Net y OleDB
Primeramente recordar usar este using:
Todo el secreto esta en la conexión
Aqui hay varios aspectos a tomar en cuenta:
- Primeramente el Data Source puede ser tanto una carpeta local, como en este caso, o bien una carpeta compartida o DFS (p.e. \\DFS\Pruebas\test.xls)
- Lo que vamos a hacer es una consulta SQL del Excel por lo que si en Extended Properties indicamos que HDR=YES, estamos diciendo que el primer valor de las celdas es el nombre con el que se conoceran las columas. Asi si tenemos un excel en el primer valor de cada columna, o encabezado, es PRODUCTO, CANTIDAD, PRECIO entonces podriamos hacer:
-Ademas debemos tener en cuenta que el IMEX=1 en Extended Properties significa que se tomaran los valor tal y como se FORMATEAN en las celdas, esto es muy importante porque por ejemplo si el valor de la celda es un número, supongamos 1000000 y se encuentra formateado como monto (1,000,000.00) es posible que sea mejor eliminar el tag IMEX del todo para usar el valor real de la celda en lugar del ya formateado para evitar errores de conversión de tipos.
Seguidamente hacemos la consulta:
La primera instrucción lo que hace es extraer en un DataTable el schema del excel para poder sacar el nombre de las hojas, esto es importante porque en el si Excel esta en español las hojas se denominan Hoja1$, Hoja2$, etc.. y si esta ingles Sheet1$, Sheet2$, etc ademas puede tener un nombre personalizado y con esta instrucción podemos desentendernos de este aspecto.
Las demás instrucciones realizan la consulta usando OleDbCommand y OleDbDataAdapter para dejar la información que necesitamos en un DataTable y a partir de que lo podemos manipular como mejor nos convenga
Gracias una vez más a Pigo Sama por su inmensa sabiduría.
Como sugerencia del departamento de sistemas del cliente se nos indicó que utilizáramos Dtsx para realizar esa operación y de hecho llegamos un solución con paquetes SSIS. Sin embargo se nos complicó por una cuestión de permisos. Finalmente optamos por hacer una solución basada en OleDB más sencilla y más fácil para darle mantenimiento.
¿Y el rendimiento? pues ninguna diferencia porque resulta que los Dtsx para manejar excel utiliza OleDb. He aquí parte de la solución con .Net y OleDB
Primeramente recordar usar este using:
using System.Data.OleDb;
Todo el secreto esta en la conexión
OleDbConnection cnnOle = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:Pruebas\test.xls;Extended Properties=\"EXCEL 8.0;HDR=NO;IMEX=1\";"); cnnOle.Open();
Aqui hay varios aspectos a tomar en cuenta:
- Primeramente el Data Source puede ser tanto una carpeta local, como en este caso, o bien una carpeta compartida o DFS (p.e. \\DFS\Pruebas\test.xls)
- Lo que vamos a hacer es una consulta SQL del Excel por lo que si en Extended Properties indicamos que HDR=YES, estamos diciendo que el primer valor de las celdas es el nombre con el que se conoceran las columas. Asi si tenemos un excel en el primer valor de cada columna, o encabezado, es PRODUCTO, CANTIDAD, PRECIO entonces podriamos hacer:
SELECT PRODUCTO, CANTIDAD, PRECIO FROM [Sheet1$]Pero si usamos HDR=NO, usamos el nombre generico (F1, F2.,..) de las columnas, incluyendo, obviamente, el primer valor de cada columna como valores que nos devolvera la consulta
-Ademas debemos tener en cuenta que el IMEX=1 en Extended Properties significa que se tomaran los valor tal y como se FORMATEAN en las celdas, esto es muy importante porque por ejemplo si el valor de la celda es un número, supongamos 1000000 y se encuentra formateado como monto (1,000,000.00) es posible que sea mejor eliminar el tag IMEX del todo para usar el valor real de la celda en lugar del ya formateado para evitar errores de conversión de tipos.
Seguidamente hacemos la consulta:
DataTable schemaTable = cnnOle.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }); OleDbCommand cmdOle = new OleDbCommand("SELECT F1,F2,F3 FROM [" + schemaTable.Rows[0]["Table_Name"].ToString() + "]", cnnOle); OleDbDataAdapter daOle = new OleDbDataAdapter(cmdOle); dt = new DataTable(); daOle.Fill(dt);
La primera instrucción lo que hace es extraer en un DataTable el schema del excel para poder sacar el nombre de las hojas, esto es importante porque en el si Excel esta en español las hojas se denominan Hoja1$, Hoja2$, etc.. y si esta ingles Sheet1$, Sheet2$, etc ademas puede tener un nombre personalizado y con esta instrucción podemos desentendernos de este aspecto.
Las demás instrucciones realizan la consulta usando OleDbCommand y OleDbDataAdapter para dejar la información que necesitamos en un DataTable y a partir de que lo podemos manipular como mejor nos convenga
Gracias una vez más a Pigo Sama por su inmensa sabiduría.
18 jun 2009
Ubuntu puesta al día
Por febrero del presente año, de nuevo había escuchado el llamado...Entonces comencé con el Ubuntu 8.10 Intrepid, dejándome un grato sabor de boca.
Hoy cinco meses después toca una puesta al día de mi ubuntesca incursión. Comencemos por el cambio, Sí, cambié de 8.10 intrepid a Ultimate 2.0. ¿La razón? La desconexión.
Como no pude hacer que Ubuntu reconociera mi winmodem, pues no me podía conectar a Internet, como no me podía conectar pues las actualizaciones eran un dolor de cabeza. Navegando por Internet me encontré con el Ubuntu Ultimate Gamers Edition para ser exactos. Desinstalé mi intrepid e instalé la nueva adquisición y "voila!" TODOS los codec de vídeo (lo que más necesitaba) estaban listos y armados. Nada de andar buscando paquetes adicionales ni dependencias. Perfecto!

Después me di cuenta que mi hacía falta los necesarios para ver video rmv pero era un mal menor que puede superar rápidamente. Ahorita puedo ver todos mis capítulos de anime,escuchar mis mp3, tengo mi suite de ofimática (OpenOffice), tengo máquinas virtuales de windows montadas sobre VirtualBox para mi trabajo en .Net todas comunicándose por virual networking, instalados los drivers Nvidia, juego ocasionalmente con el gridwars o Chromium y hasta ocurrió el milagro de poder instalar mi nuevo winmodem (el anterior pasó a mejor vida) este post lo hice desde Ubuntu!
Conclusión: Aunque el cambio es algo brusco y no muy fácil, voy aprendiendo, ya se me va quitando el miedo a la terminal, aunque a veces tengo que hacer una pausa para pensar ¿que estoy haciendo? ya que no se trata de copiar y pegar en la consola si no tratar de entender que estoy haciendo. Sin embargo en términos generales estoy muy satisfecho con el Ultimate, facilita bastante esa transición, aunque aún tengo Windows XP instalado para jugar el COD Modern Warfare :-)
Hoy cinco meses después toca una puesta al día de mi ubuntesca incursión. Comencemos por el cambio, Sí, cambié de 8.10 intrepid a Ultimate 2.0. ¿La razón? La desconexión.
Como no pude hacer que Ubuntu reconociera mi winmodem, pues no me podía conectar a Internet, como no me podía conectar pues las actualizaciones eran un dolor de cabeza. Navegando por Internet me encontré con el Ubuntu Ultimate Gamers Edition para ser exactos. Desinstalé mi intrepid e instalé la nueva adquisición y "voila!" TODOS los codec de vídeo (lo que más necesitaba) estaban listos y armados. Nada de andar buscando paquetes adicionales ni dependencias. Perfecto!

Después me di cuenta que mi hacía falta los necesarios para ver video rmv pero era un mal menor que puede superar rápidamente. Ahorita puedo ver todos mis capítulos de anime,escuchar mis mp3, tengo mi suite de ofimática (OpenOffice), tengo máquinas virtuales de windows montadas sobre VirtualBox para mi trabajo en .Net todas comunicándose por virual networking, instalados los drivers Nvidia, juego ocasionalmente con el gridwars o Chromium y hasta ocurrió el milagro de poder instalar mi nuevo winmodem (el anterior pasó a mejor vida) este post lo hice desde Ubuntu!
Conclusión: Aunque el cambio es algo brusco y no muy fácil, voy aprendiendo, ya se me va quitando el miedo a la terminal, aunque a veces tengo que hacer una pausa para pensar ¿que estoy haciendo? ya que no se trata de copiar y pegar en la consola si no tratar de entender que estoy haciendo. Sin embargo en términos generales estoy muy satisfecho con el Ultimate, facilita bastante esa transición, aunque aún tengo Windows XP instalado para jugar el COD Modern Warfare :-)
12 jun 2009
Null y DBNull hermanos pero no gemelos
Hace poco me encontré con que este código
Object cannot be cast from DBNull to other types
Resulta que la variable monto_evaluar estaba declarada como object y ademas se obtenía directamente de un Dataset. Pues bien cuando se hacen cosas como estas hay que tener en mente que desde la base de datos en caso de que el dato este nulo, no se devuelve un null si no un tipo dato DBNull. Ellos son hermanos pero no gemelos, significan prácticamente lo mismo pero son tipos de dato diferentes y, adicionalmente, si un objeto es de tipo DBNull no se puede castear (convertir) en ningún otro tipo ni siquiera para comparar y éste es precisamente el error que se nos muestra.
La línea de código debe quedar como sigue:
De esta forma comparamos utilizando el tipo de dato correcto.
Total= (monto_evaluar== null) ? 0 : Convert.ToDecimal(monto_evaluar);
genera el error:Object cannot be cast from DBNull to other types
Resulta que la variable monto_evaluar estaba declarada como object y ademas se obtenía directamente de un Dataset. Pues bien cuando se hacen cosas como estas hay que tener en mente que desde la base de datos en caso de que el dato este nulo, no se devuelve un null si no un tipo dato DBNull. Ellos son hermanos pero no gemelos, significan prácticamente lo mismo pero son tipos de dato diferentes y, adicionalmente, si un objeto es de tipo DBNull no se puede castear (convertir) en ningún otro tipo ni siquiera para comparar y éste es precisamente el error que se nos muestra.
La línea de código debe quedar como sigue:
Total=(monto_evaluar== System.DBNull.Value) ? 0 : Convert.ToDecimal(monto_evaluar);
De esta forma comparamos utilizando el tipo de dato correcto.
25 may 2009
Cómo pasar variables a un DTSX
Recientemente he tenido que "agarrarme" (como decimos en Tiquicia) con los Dtsx (la evolución de los tan útiles Dts de Sql Server 2000 ahora enmarcado en los paquetes SSIS de Sql Server 2005).
La cuestión es que ya cargado dentro de un componente .Net necesitaba pesarle el valor de unas variables que había declarado dentro del Dtsx como si de parámetros se tratasen. Cumplí este cometido de la siguiente manera:
Se requiere el siguiente using para trabajar con Dtsx:
y luego el siguiente código como parte del método correspondiente:
Variable1 y Variable2 son variables globales a nivel del dtsx las cuales por medio del VariableDispenser son accesibles tanto de escritura como en este caso o de lectura si se requierese. Siempre hay que hacer un Unlock de las variables antes de ejecutar el paquete .
Otra cosa interesante es la detección de errores de DTSX dentro de ambiente .Net, Éstos se almacenan en la colección Errors del paquete. En este caso se dispara una excepción cuya descripción es la del primer error en dicha colección pero se puede hacer de forma más elaborada almacenando toda la colección de errores usando la instrumentación para ello, por ejemplo.
La cuestión es que ya cargado dentro de un componente .Net necesitaba pesarle el valor de unas variables que había declarado dentro del Dtsx como si de parámetros se tratasen. Cumplí este cometido de la siguiente manera:
Se requiere el siguiente using para trabajar con Dtsx:
using Microsoft.SqlServer.Dts.Runtime;
y luego el siguiente código como parte del método correspondiente:
Package myPackage; Application integrationServices = new Application(); string packagePath= System.Configuration.ConfigurationManager.AppSettings["DTSXPATH"]; myPackage = integrationServices.LoadPackage(packagePath, null); Variables vars = null; myPackage.VariableDispenser.LockForWrite("variable1"); myPackage.VariableDispenser.LockForWrite("variable2"); myPackage.VariableDispenser.GetVariables(ref vars); try { foreach (Variable v in vars) { switch (v.Name) { case "variable1": v.Value = "lo que quiera pasar para la variable1"; break; case "variable2": v.Value = "lo que quiera pasar para la variable2"; break; } } } catch (Exception ex) { throw ex; } finally { vars.Unlock(); } DTSExecResult local_DTSExecResult = myPackage.Execute(); if (local_DTSExecResult == Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure) { foreach (DtsError local_DtsError in myPackage.Errors) { throw new Exception(local_DtsError.Description); } }
Variable1 y Variable2 son variables globales a nivel del dtsx las cuales por medio del VariableDispenser son accesibles tanto de escritura como en este caso o de lectura si se requierese. Siempre hay que hacer un Unlock de las variables antes de ejecutar el paquete .
Otra cosa interesante es la detección de errores de DTSX dentro de ambiente .Net, Éstos se almacenan en la colección Errors del paquete. En este caso se dispara una excepción cuya descripción es la del primer error en dicha colección pero se puede hacer de forma más elaborada almacenando toda la colección de errores usando la instrumentación para ello, por ejemplo.
Suscribirse a:
Entradas (Atom)