Category: HowTo

Dec 07 2006

Tirar todos los usuarios de un servidor

Hace poco, nos surgió en el curro la necesidad de preparar un script o algo por el estilo que nos sirva para tirar a todos los usuarios de un servidor sin recurrir a la consola de Citrix. Estuvimos un tiempo mascando la idea, y al final, preparamos un script en VBS que a base de dos comandos de Terminal Services nos tira a todos los usuarios conectados a un servidor en concreto. El detalle importante aqui es que los comandos son a nivel de Terminal Server y con el alcance únicamente del servidor en el que se ejecutan.

Los dos comandos que vamos a utilizar son query session y logoff nombre_de_sesion. El primero de los dos, nos devuelve las sesiones que están ejecutándose actualmente en ese servidor y el segundo cierra la sesión que le pasamos. Entonces, si lanzamos el query session para ver que hace, por curiosidad, vemos que entre otras cosas, devuelve las sesiones abiertas en escucha, tanto las de Citrix (que son ica-tcp) como las de escritorio remoto de Windows (rdp-tcp). Cuando lancemos el script sólo queremos tirar las sesiones conectadas a Citrix, por lo tanto, no hay que tirar ni las de escucha, ni las de rdp. Fijándonos bien, vimos que las sesiones de Citrix se llaman todas ica-tcp#X donde la X es el número de sesión, por lo tanto, cogiendo los resultados del primer comando y lanzando el segundo sobre lo que se llame ica-tcp# y lo que sea, lo tendremos. Pues este es el script:

Dim objShell, objEjec, objTira, Linea

Set objShell=CreateObject(”WScript.Shell”)
Set objEjec=objShell.Exec(”query session”)
Do While Not objEjec.StdOut.AtEndOfStream
Linea=objEjec.StdOut.ReadLine
If InStr(Linea,”ica-tcp#”) Then
Linea=Right(Linea,Len(Linea)-1)
Linea=Left(Linea,InStr(Linea,” “)-1)
Set objTira=objShell.Exec(”logoff ” & Linea)
End If
Loop

Pues nada, con eso, a tirar usuarios a punta y pala

Nov 21 2006

.NET: Uso provechoso del Application_Error del Global.asax

Nuestro compa JLL (esker anitz!) nos manda el siguiente texto para nuestra lectura. El codigo está en C#. Es un pequeño manual de cara a capturar los errores que surjan fuera de los TryCatch:

El evento Application_Error que hay en el archivo Global.asax se dispara cuando salta una excepción en la aplicación ASP.NET y no la hemos cazado en un bloque TryCatch. Usaremos este evento para guardar los datos de la excepción en un archivo de log. Para obtener el objeto excepción, llamamos a la la función Server.GetLastError() que nos da el objeto excepción. Este sería el código que habría que poner en el global.asax para que nos grabara un archivo de log en el directorio /logs de la aplicación (Debe estar creado y tener permisos de escritura):

using System.IO;
using System;
using System.Text;



protected void Application_Error(Object sender, EventArgs e)
{
//Funcion que escribe los detalles de una excepción cuando esta se genera en un log
Exception ex = this.Server.GetLastError().GetBaseException();

StreamWriter L_fichero = new StreamWriter(System.AppDomain.CurrentDomain.BaseDirectory + “/logs/App.log”, true);
L_fichero.WriteLine(”******************”);
L_fichero.WriteLine();
L_fichero.WriteLine(System.DateTime.Now.Hour.ToString() + “:” + System.DateTime.Now.Minute.ToString()+ “:” + System.DateTime.Now.Second.ToString());
L_fichero.WriteLine(”Descripción: ” + ex.Message);
L_fichero.WriteLine(”Origen:” + ex.Source);
L_fichero.WriteLine(”Pila:” + ex.StackTrace);
L_fichero.WriteLine();
L_fichero.WriteLine(”*****************”);
L_fichero.Flush();
L_fichero.Close();
}

Nov 08 2006

Instalar la Consola de Administración de Citrix en local

Bueno, lo primero voy a empezar por explicar un poco el tema de este post. Cuando tienes montada una granja de Citrix, a la hora de controlarla y gestionarla, utilizas una aplicación llamada Consola de Administración (Management Console, según ellos). Nosotros aqui, la tenemos instalada en el nodo principal de la granja, y la tenemos publicada para el grupo de Administradores, de manera que cuando queremos entrar, la ejecutamos como una aplicación más a través de Citrix. Esto tiene como contra que le cuesta un rato abrirse, ya que cuando no tienes nada abierto porque estás trabajando con las herramientas en local, tienes que ir al Web Interface, logarte, lanzar la aplicación, y esperar a que se abra (logon en el servidor y demás). Entonces, si lo que quieres es abrir la consola para mirar una cosa puntual, la verdad es que le cuesta más de lo que, al menos yo, estamos dispuestos a esperar.

Así que hace algún tiempo, un compañero y yo tratamos de instalarla en local para evitarnos toda la espera, símplemente la ejecutas y te conectas a la granja … mucho menos tiempo de espera. La instalamos con el CD de Citrix, y todo parecía que iba bien, se instaló satisfactoriamente (o eso decía el programilla), pero al ir a ejecutar, tacatá …

Error numero 1

Vamos, que algo no estaba del todo bien, bueno, no pasa nada, errores le salen a cualquiera ¿no?, veamos que nos dice cuando conocemos los detalles:

Error numero 2

Viendo los detalles que son un poco escasos, dedujimos que había algún error en el directorio donde se instala o algo por el estilo, pero nada más lejos de la realidad.
Resulta que la consola está hecha en Java, por lo que necesitas la Máquina Virtual de Java, y no cualquier máquina, la de la versión 1.4, pero en la instalación que hace, te instala la versión 1.4.0_06 (pequeño detalle a tener en cuenta). Para que la consola no se de cuenta, te crea 2 claves en el registro de Windows idénticas, pero con los nombres 1.4 y 1.4.0_06 donde se indica la ruta del ejecutable de la Máquina Virtual y demás parafernalia, estas claves se ubican en “HKLM\SOFTWARE\JavaSoft\Java Runtime Environment”.
Por tanto, hasta ahora, con todo lo dicho, debería funcionar correctamente y no dar problemas como el que nos daba ¿no? Pues a veces si, si no tienes ninguna Máquina Virtual de Java instalada previamente, genial, te lo hace bien, y todos amigos, pero si tienes (por ejemplo) como era nuestro caso, la Máquina Virtual 1.5 ya instalada, el instalador de la consola no se esfuerza mucho, y sólo te instala la clave 1.4.0_06, con lo que la consola nos deleita con esos maravillosos errores que nos tuvieron mal encaminados una buena temporada.
Gracias a mi compañero JoseMi, que sacó la solución y me la dijo para poder instalarla, ya tenemos las consolas en local, y haciendo pruebas, he llegado a la conclusión, que el instalador, si ve que tenemos alguna otra clave en el registro parecida, ya sea la 1.5, o la 1.4.0_06, no crea la clave 1.4, si no la tenemos, la instala, pero no crea la segunda clave.

Y bueno, ya la solución, si instalamos la consola, y nos da este fallo, accedemos al registro, buscamos esa clave, y renombramos la que pone 1.4.0_06 por 1.4 sin nada más, ni puntos al final, ni al principio ni nada, que si no, no nos funcionará, hecho esto, salimos, abrimos la consola, y a funcionar, mucho más rápido que de la otra manera.

Nov 07 2006

ORACLE: Crear esquema

Hasta el momento hemos comentado como se hacen las exports, las import,… pero no hemos hablado de cómo crear un esquema en oracle. Para ello basta con lanzar este sencillo script, pero antes debemos comprobar un par de cuestiones.

Los datos a comprobar es la ruta donde se almacenan los tablespace en nuestro Oracle, así como el nombre del tablespace temporal. El tablespace es un espacio de tablas es una división lógica de una base de datos. Toda base de datos consta, al menos, de un espacio de tablas (llamado espacio de tablas SYSTEM). Se pueden utilizar otros espacios de tablas para agrupar a los usuarios o aplicaciones, con el fin de facilitar el mantenimiento y mejorar el rendimiento. Algunos ejemplos de estos espacios de tablas pueden ser: USERS (para uso general) y UNDO (para deshacer cambios) [1]. Una vez lo hallamos comprobado, los ponemos en el script y lo lanzamos.

Lo primero que hay que crear son los dos tablespace, para el Nombre_data y para el Nombre_index (pudiendo ser Nombre lo que queramos). En este ejemplo crearemos un esquema llamado Compras y a los tablespace los llamaremos Comp_data y Comp_index

CREATE TABLESPACE "COMP_DATA"
LOGGING
DATAFILE 'D:\ORACLE\ORADATA\OR92\COMP_DATA1.ora' SIZE 50M
REUSE AUTOEXTEND
ON NEXT 10240K MAXSIZE 32767M EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;
CREATE TABLESPACE "COMP_INDEX"
LOGGING
DATAFILE 'D:\ORACLE\ORADATA\OR92\COMP_INDEX1.ora' SIZE 50M
REUSE AUTOEXTEND
ON NEXT 10240K MAXSIZE 32767M EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;

Y ahora nos creamos al usuario con unos permisos, etc… que manejará estos tablespace:

CREATE USER "COMPRAS" PROFILE "DEFAULT"
IDENTIFIED BY "COMPRAS" DEFAULT TABLESPACE "COMP_DATA"
TEMPORARY TABLESPACE "TEMP"
QUOTA UNLIMITED ON "COMP_DATA"
QUOTA UNLIMITED ON "COMP_INDEX"
QUOTA UNLIMITED ON "TEMP"
ACCOUNT UNLOCK;
GRANT "CONNECT" TO "COMPRAS";
GRANT "RESOURCE" TO "COMPRAS";
REVOKE UNLIMITED TABLESPACE FROM "COMPRAS";

Y así ya tenemos creado el esquema Compras, por lo que ya podemos jugar con él, jiji.

[1] definición de tablespace sacada de ajpdsoft

Nov 07 2006

ASP.NET: POPUPS DINAMICOS

Vía mail, un compa del curro nos manda el siguiente HowTo. Como siempre os podéis bajar el texto en su formato (y tonterías;) original en el link que encontrarás al final del post.

[begin HowTo]

Uno de los problemas que podemos encontrar a la hora de utilizar javascript desde asp.net puede ser que requiera interactuar con el contenido del código ejecutado en el servidor, así que hay que ingeniárselas para conseguirlo. Imaginad que tenemos un dropdownlist y una imagen, y que al pulsar la imagen queremos abrir un popup que nos lleve a la ruta indicada en el dropdownlist. Si metemos el javascript a pelo vamos mal, ya que no sabemos el contenido de ese dropdownlist, así que tenemos que buscarle las cosquillas al tema.

Muchos ya conoceréis la función RegisterStartupScript, que será la que usemos para este ejercicio. Aquí esta la función que utilizaremos:

Private Sub abreURL(ByVal ventana As String)
Dim ClientScript As String = String.Concat("<script>window.open('", ventana, "')</script>")
If Not Me.IsStartupScriptRegistered("WindowOpen") Then
Me.RegisterStartupScript("WindowOpen", ClientScript)
End If
End Sub

Fácil verdad? Únicamente creamos una función que reciba el valor de la ventana (del dropdownlist le pasamos SelectedItem, o SelectedValue, lo que tengamos que pasarle) y registramos el script que abre la ventana ;).

Ahora hay que llamar a esta función. Así de simple:

Private Sub imgURL_Click(ByVal sender As System.Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles imgURL.Click
abreURL(ddlSupuesto.SelectedValue)
End Sub

En este caso tenemos un ImageButton que al pulsarlo llamará a la función, la función se encarga de recoger el valor y forzar a la pagina a llamar a javascript para abrir la pagina que acabamos de introducir desde el dropdownlist.

Espero que os sea útil ;).

Eneko Apaolaza

[end HowTo]

[download]: aquí

Nov 06 2006

.NET: Generar instalador

Hoy me ha llegado la siguiente duda (se dice el pecado pero no el pecador) vía mail:

…echame un cable please con algo que aunque parezca mentira no he hecho nunca: tengo un grupo de proyectos con dos dll (una de ellas referencia a la otra) y un exe que referencia a las dos. Quiero generar el ejecutable y empaquetarlo para instalarlo en otros equipos, como rayos se hace!!!, me estoy peleando con el asistente de empaquetado pero no lo entiendo…

Pues bien, como yo tampoco lo he hecho nunca (en casa de herrero…;), un compa nos manda un miniresumen de cómo hacerlo (esker anitz Sergei!):

[begin HowTo]

Primero hay que crear un proyecto de setup. Para ello con el proyecto abierto (el del exe) , encima de la solution, boton derecho y “add new project” , en la ventana que se abre a la derecha (Project types) elegimos “setup and deployment project” y dentro de los que nos ofrece este Project type, elegimos (en templades) “setup project”. De esta manera se genera un proyecto de setup (instalador) Para Windows.

HowTo instalador

A continuación encima del proyecto que se acaba de crear, boton derecho, “add Project output” y se elige el proyecto el cual es el exe. Y veremos que en detected dependencias ha introducido todas las dll que usa el projecto, así como el “primary output from …” que es el exe.
Luego con compilar este proyecto se crea un exe (.msi) que es el instalador, e instala la aplicación que se ha introducido.
Un saludo.

[end HowTo]

[!] Lo único que la pregunta era para VB6 y no .NET jiji. A la tarde paso por tu casa e intentamos hacerlo (el ejecutable, que estamos siempre pensando en lo único).

Oct 26 2006

.NET: Contador para textbox multilínea

Un compa me manda el siguiente HowTo para uso y disfrute de todos. Como de costumbre, al final del texto teneis el .zip para que os lo bajeis en su formato original. Espero que os sirva!

[begin HowTo]

Como bien sabéis, los textbox tienen una propiedad MaxLenght para controlar cuántos caracteres se pueden escribir. Sin embargo, cuando el textbox es multilínea perdemos esa propiedad. La solución a esto es introducir un validator en el que comprobar desde el codebehind que el contenido del textbox multilínea que se ha introducido es menor o igual del que queremos que se introduzca (después cada uno lo hace a su manera, comprobarlo al pulsar el botón de enviar, mostrar un mensaje en el mismo validator o borrar el contenido…)

La principal pega del asunto es que el usuario puede que desconozca que hay una longitud máxima, introduzca un texto demasiado largo, y le muestre el mensaje de error del tipo “meeec! Campo demasiado largo!”. Así que hale, a borrar y meter menos caracteres hasta que se ajuste. Si es un campo de 10 caracteres se supone que el usuario puede contarlos, pero si es un campo de 10000 caracteres y tiene que ir contando para ver si entra es un engorro.

Ahora veremos como poner un contador que vaya mostrando los caracteres que se han introducido desde javascript, para evitar que el usuario introduzca más de la cuenta y para ayudarle a corregir su contenido en caso de que corte y pegue (por ejemplo) y su longitud sea excesiva.

Lo primero que debemos hacer es introducir un div donde mostraremos el contador:

<DIV id=”txtDescripcionCont” style=”DISPLAY: Inline”></DIV>

Destacamos la id, que la dividiremos en dos partes: cogemos el nombre del textbox que queremos contar y le añadimos “Cont” al final (se puede modificar, pero en este ejemplo lo hacemos así). Por ejemplo, si queremos contar los caracteres del textbox txtPrueba, al div le llamamos txtPruebaCont.

Vayamos ahora al codebehind y añadamos una función para registrar el javascript que se encargara de todo. Primero os muestro el javascript limpito para analizar su código:

<script language="javascript">
function cuentaCaracteres(casilla, max)
{
var caja;
var contador;
caja = document.getElementById(casilla).value;
contador = document.getElementById(casilla + 'Cont');
contador.innerHTML = '(' + caja.length + '/' + max + ')';
}
</script>

La función cuenta con dos parámetros. El primero nos indica qué casilla queremos contar, el segundo cuántos caracteres máximos debe tener.

Recogemos en caja la id de la casilla que le proporcionamos, y en contador recogemos el div (concatenando la id de la casilla con “Cont”, de ahí que os dijera antes que añadíamos este sufijo al final). Ahora simplemente introducimos en el contador la longitud actual del contenido de la casilla (caja.length) y la longitud máxima (max), formateándolo para que quede bonito.

Vale, la función es muy simple verdad? Ahora veamos como la vamos a introducir en el CodeBehind:

Private Sub registra_javascript()
Dim javascript As String
javascript = "<script language='javascript'>"
javascript = String.Concat(javascript, "function cuentaCaracteres(casilla, max)")
javascript = String.Concat(javascript, "{var caja;var contador;caja = document.getElementById(casilla).value;")
javascript = String.Concat(javascript, "contador = document.getElementById(casilla + 'Cont');")
javascript = String.Concat(javascript, "contador.innerHTML = '(' + caja.length + '/' + max + ')';}")
javascript = String.Concat(javascript, "</script>")
Page.RegisterStartupScript("js", javascript)
txtDescripcion.Attributes.Add("onKeyUp", "cuentaCaracteres(this.id, '250')")
body.Attributes.Add("onLoad", "cuentaCaracteres('txtDescripcion', '250')")
End Sub

En primer lugar metemos la función en la variable “javascript”. Registramos con RegisterStartupScript el código javascript, y le añadimos comportamiento al campo txtDescripcion para que cuente los caracteres en el evento onKeyUp. De esta manera, cada vez que pulse una tecla se refrescara el contador y nos ira contando los caracteres al irse tecleando.

Destaco también los parámetros que enviamos para el evento onKeyUp. En primer lugar está la id del control que mira el contador (txtDescripcion), que se le facilita con “this.id”. En segundo lugar está el número de caracteres máximo.

Después de eso tenemos una pequeña pega: al abrir la pagina en principio el contador esta en blanco. Para solucionar esto tenemos la última línea, donde le decimos a “body” que cuando cargue llame a la función, para conseguir que se refresque al entrar. Aquí no le pasamos “this.id” como en el anterior, sino directamente el nombre del textbox que queremos inicializar.

Si queremos inicializar varios textbox, podremos hacerlo de la siguiente manera:

Dim sLoad As String
sLoad = "cuentaCaracteres('txtTitulo', '70')"
sLoad = String.Concat(sLoad, ";cuentaCaracteres('txtDescripcion', '200')")
body.Attributes.Add("onLoad", sLoad)

Es simple. Únicamente añadimos la llamada a la primera función y por cada llamada que vayamos a hacer, la concatenamos con la primera (no os olvidéis del ; que va entre función y función). Para terminar, se añade atributo, y se le pasa “sLoad”.

Ya solo nos queda definir body. En el código aspx debemos modificar el body (que en principio es solamente) y lo cambiamos por esto:

<BODY runat=”Server” id=”body”>

Con esto ya podemos controlarlo desde el CodeBehind y podemos añadirle el atributo. Para terminar, declaramos el body en el código:

Protected WithEvents body As System.Web.UI.HtmlControls.HtmlGenericControl

Y eso es todo. Como veis es un ejemplo sencillote y modificable, así que podéis complicarlo como a vosotros os parezca. Espero que os sea de ayuda.

Eneko Apaolaza

[end HowTo]

[Download]: texto completo aquí

Oct 23 2006

Localización de sitios Web con ASP.Net en Visual Studio 2005 [enterico]

Aunque en un principio lo íbamos a publicar por partes, al final, vamos a poner de golpe todo el HowTo, así como el fichero .zip tanto con el texto como con el código de ejemplo. Creo que os facilitará la comprensión del tema si lo publicamos de golpe y no a partes, no nos vaya a pasar como con Ghost in the Cell, que los veo de ciento a viento y me tengo que mirar el capítulo anterior para saber de que va el nuevo. Menos mal que lo veo desde emuleTV, que me permite repetir los capítulos, je je.

Esker anitz Jesus Mari por este HowTo!

[begin HowTo]

Definición de la cultura en la página:

En primer lugar debemos de indicar a la página la cultura que debe usar. Para ello existen dos propiedades, contenidas dentro de la clase System.Web.UI.Page:

UICulture: establece la cultura de la interface de usuario, es decir la que más tarde nos servirá para establecer relación con el texto en varios lenguajes
Culture: establece la referencia cultural en la que se basa y comporta la página; esta propiedad cambia todo lo referente a la fecha, moneda y todas las características específicas de la cultura seleccionada. No afecta a las traducciones de los diferentes lenguajes, pero en ciertos controles como Asp.Calendar, afecta también a cambiar el lenguaje.

Estas propiedades son de tipo “string“, contenidas dentro de la propia página, cuando queremos asignarles una cultura se debe poner su identificador: “es-ES”, etc., pero el valor que nos devuelve no es el identificador, sino su descripción: “Español (España)”. Para obtener el identificador actual debemos ir a la propiedad:

System.Threading.Thread.CurrentThread.CurrentUICulture.Name
Culture = System.Threading.Thread.CurrentThread.CurrentCulture.Name

Los posibles valores están definidos en el siguiente enlace, pero consta de una primera parte que es la cultura en letras minúsculas, un guión y el país en letras mayúsculas.
Aparte de un valor especifico de cultura como “es-ES”, “eu-ES”, etc., en la página existe una forma de indicar que sea la cultura predeterminada: “auto”, la cual es la que se define en el archivo de recursos por defecto (tema que se explica mas adelante).

Formas de cambiar la cultura dentro de la página:

Definida en la directiva de la página:

<%@ Page UICulture=”es-ES” Culture=”es-ES”>

Definida en el web.config: afecta a todas las páginas, excepto a las que ya lo tengan definidas en la directiva de la página (caso anterior).

<system.web>
<globalization uiCulture="es-ES" culture="es-ES" />
</system.web>

Definida dinámicamente:

Se puede definir en ejecución una cultura diferente, para ello simplemente se debe sobre escribir el evento InitializeCulture. Es en el único evento en el que se puede hacer:

protected override void InitializeCulture()
{
Page.Culture = “es-ES”;
Page.UICulture = “es-ES”;
base.InitializeCulture();
}

Creación de un archivo de recursos:

Para definir las posibles culturas, se debe realizar mediante la creación de archivos de recursos, que son de tipo xml. Estos archivos son compilados en un ensamblado satélite, en tiempo de ejecución, esto quiere decir que no es necesario compilar todo el sitio Web ni para modificarlos, ni para añadir una nueva cultura con un nuevo recurso.

Desde Visual Studio han proporcionado dos métodos para acceder a estos archivos: cursos globales y locales:

Recursos globales:

Tienen la ventaja de que son accesibles desde todo el sitio Web de donde están definidos, y que son gestionados por el “inteligence” de Visual Studio, por lo que facilita trabajo al desarrollador. Aunque tienen las desventajas del rendimiento de la página, ya que debe ejecutar el ensamblado en ejecución, y al ser global y compilar todos los recursos, le cuesta más tiempo; y al enlazar el recurso con un control Web, existen varios métodos, se explicará mas tarde, y uno de ellos bastante cómodo no existe en los recursos globales.

Se parte siempre de la base de que por cada página .aspx, debe existir un archivo que sea el idioma por defecto, el nombre de este puede cualquiera, pero se recomiendo que sea el mismo de la página, luego por cada cultura, existirá otro archivo, con el mismo nombre que el archivo de recursos principal, pero con la cultura:

Archivo por defecto:

[Cualquier nombre].resx

Archivo de cultura:

[Nombre del archivo por defecto].[cultura].resx

Estos archivos deben estar dentro del sitio Web en la carpeta

App_GlobalResources

Por ejemplo si tenemos la página “prueba.aspx”, debe existir siempre un archivo que podría ser “App_GlobalResources\prueba.resx”, que sería con la cultura por defecto, luego para la cultura en castellano “es-ES” habría que crear un archivo que sea “App_GlobalResources\prueba.es-ES.resx”, y así sucesivamente por cada cultura. Por defecto si la cultura es en castellano, intentará acceder al archivo de castellano “App_GlobalResources\prueba.es-ES.resx”, pero si al buscar una fila de la etiqueta no la encontraría se buscaría en el archivo por defecto “App_GlobalResources\prueba.resx”.

Enlazar el texto con la página en diseño:

Dentro del control se podría poner a la propiedad “Text” el siguiente valor:

Text="<%$ Resources:[Nombre de la clase], [Key de la fila] %>”

Siguiendo el ejemplo anterior, si en los archivos “prueba.resx” y “prueba.es-ES.resx” tendríamos un nodo que sería “label1Text” con un valor cualquiera, se escribiría:

<asp:Label ID="label1" runat="server" Text="<%$ Resources:RecursosGlobalesIdiomaDefWebConfig, label1Text %>" ></asp:Label>

Desde el modo diseño de la página, en la propiedades del control (F4), en “Expressions”, “Text”, aparece una opción donde si elegimos como tipo: “Resources”, clase: el nombre de la clase y “Resource Key”: la clave de la fila, auto genera lo mismo el código anterior.

lblApplicationname Expressions

Enlazar el texto en ejecución:

En modo de ejecución resulta mas fácil, gracias al “inteligence” de Visual Studio, se puede acceder cómodamente a todas los recursos de la página. Existe la clase “Resources” que contiene una colección de todas las clases de recursos, que a su vez contiene una colección con todas las claves de esa clase. Siguiendo el ejemplo anterior:

protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Resources.prueba.label1Text;
}

Recursos locales:

A diferencia de los recursos globales, solo son accesibles desde la carpeta donde está ubicado la página .aspx, es decir habrá una carpeta de recursos por cada carpeta donde existen páginas, esto implica que cuesta menos su ejecución, aunque es mas difícil localizar todos los recursos en un único sitio. No aparecen en el “inteligence” de Visual Studio en la clase “Resources”, pero son más fáciles de enlazar en modo diseño.

Se parte también de la base de que por cada página .aspx, debe existir un archivo que sea el idioma por defecto, el nombre debe ser siempre el mismo que el de la página, luego por cada cultura, existirá otro archivo, con el mismo nombre que el archivo de recursos principal, pero con la cultura:

Archivo por defecto:

[Nombre de la página, incluida la extension .aspx].resx

Archivo de cultura:

[Nombre de la página, incluida la extension .aspx].[cultura].resx

Estos archivos deben estar dentro de la carpeta Web donde este la página

App_LocalResources

Por ejemplo si tenemos la página “prueba.aspx”, en la carpeta “Pruebas” debe existir un archivo que podría ser “Pruebas\App_LocalResources\prueba.aspx.resx”, que sería con la cultura por defecto, luego para la cultura en castellano “es-ES” habría que crear un archivo que sea “Pruebas\App_LocalResources\prueba.aspx.es-ES.resx”, y así sucesivamente por cada cultura. Por defecto si la cultura es en castellano, intentará acceder al archivo de castellano pero si no lo encuentra ira al archivo por defecto.

Enlazar el texto con la página en diseño:

Se puede enlazar directamente a la propiedad deseada, pero esta vez sin indicar la clase porque es un recurso local:

Text="<%$ Resources:label1.Text %>

Otra forma de enlazar que es la ventaja que tiene los recursos locales frente a los globales, es que cuando se definen, por ejemplo con el archivo “prueba.aspx.resx”, se podría definir todas las propiedades conocidas del control, como si fuera una hoja de estilos:

“prueba.aspx.resx”:
label1.Text = “hola mundo”
label1.BackColor = “Green”

Mediante la propiedad “meta:resourcekey” se puede enlazar todo el control, por ejemplo para este caso, enlazando a un control Label:

<asp:Label ID="label1" runat="server" meta:resourcekey="label1"></asp:Label>

De está forma se asigna automáticamente al a propiedad “Text” y “BackColor” del control, o las que se asignen en el futuro.

Enlazar el texto en ejecución:

Cuando son locales, no están disponibles en el “inteligence” la forma de acceder es mediante a la función “GetLocalResourceObject” que se crea en ejecución en la página. Siguiendo el ejemplo anterior:

protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = this.GetLocalResourceObject("label1.Text").ToString();
}

[end HowTo]

Y como os decía por arriba del todo aquí teneis el archivico este con el texto aquí mostrado en su maquetación original más un ejemplo en código de lo explicado:

[Download]: Localizacion_de_sitios_Web_con_ASP.zip

Oct 19 2006

Cómo Copiar una fila de un Dataset en Otro dataset, teniendo los dos la misma estructura

Si ya digo yo, que cuando uno llega a casa y se pone delante del bitxo se le va la wendy. El segundo texto del dia de Ana. ¿te unes al club? Hasta que me conteste os dejo con este HowTo de su puño y letr… y teclau.

[begin HowTo]

Logicamente la 1ª idea es:

for each row as datarow in ds2.tables(0).rows
ds1.tables(0).rows.add(ds2.tables(0).Rows(0))
next

Añadimos al ds1 la/as fila/as que queremos del ds2

Tan pronto como se intenta agregar la fila, ASP.NET indica que la fila ya pertenece a otra tabla.

Problema:

En ADO.NET no se puede compartir el mismo objeto en varios objetos contenedores. Por ejemplo, el mismo objeto DataTable no se puede agregar a dos o más objetos DataSet. Un objeto DataRow no puede aparecer en dos tablas distintas[1]

Solución:

  • 1. Obtener la/as fila/as que se desean agregar.
  • 2. Obtener una nueva tabla con el mismo esquema que el original.
  • 3. Duplicar y agregar fila/as.

Código de la solución:


For Each fila as datarow in ds2.tables(0).rows
Dim row As DataRow = Ds1.Tables(0).NewRow
row.ItemArray = ds2.Tables(0).Rows(0).ItemArray
ds1.Tables(0).Rows.Add(row)
next

Fácil y sencillo.

Por Cierto!!!! Este método hace que las filas tengan el RowState a Insert así que si se quiere mantener el rowstate la mejor manera es haciedo lo siguiente:

Dim oDSOLD As DataSet = ds2
ds1 = oDSOLD.Clone()
Ds1.tables(0).BeginLoadData()
For Each oRow As DataRow In oDSOLD.Tables(0).Rows
ds1.Tables(0).LoadDataRow(oRow.ItemArray, False)
Next
Ds1.tables(0).EndLoadData()

Parámetros:
values: Matriz de valores utilizada para crear la nueva fila.
fAcceptChanges: true para aceptar los cambios; de lo contrario, false.
Valor devuelto: Nuevo objeto DataRow.
[2]

En este caso el parametro fAcceptChanges esta a false ya que en este caso nos interesa que las filas recién agregadas se marquen como inserciones, y los cambios realizados en las filas existentes se marquen como modificaciones.

Saludos ART

[1] La clonación y el caso de la tabla Dolly, parte 2

[2] DataTable.LoadDataRow (Método) (Object[], Boolean)

[end HowTo]

Oct 16 2006

Localización de sitios Web con ASP.Net en Visual Studio 2005 [Parte I]

contexto: Un buen amigo se ha currado el siguiente HowTo, manual o como queramos llamarlo sobre la culture de sitios web con ASP.Net que nos facilitará su uso. ¡Que lo disfruteis!

[begin HowTo]

Definición de la cultura en la página:

En primer lugar debemos de indicar a la página la cultura que debe usar. Para ello existen dos propiedades, contenidas dentro de la clase System.Web.UI.Page:

UICulture: establece la cultura de la interface de usuario, es decir la que más tarde nos servirá para establecer relación con el texto en varios lenguajes
Culture: establece la referencia cultural en la que se basa y comporta la página; esta propiedad cambia todo lo referente a la fecha, moneda y todas las características específicas de la cultura seleccionada. No afecta a las traducciones de los diferentes lenguajes, pero en ciertos controles como Asp.Calendar, afecta también a cambiar el lenguaje.

Estas propiedades son de tipo “string“, contenidas dentro de la propia página, cuando queremos asignarles una cultura se debe poner su identificador: “es-ES”, etc., pero el valor que nos devuelve no es el identificador, sino su descripción: “Español (España)”. Para obtener el identificador actual debemos ir a la propiedad:

System.Threading.Thread.CurrentThread.CurrentUICulture.Name
Culture = System.Threading.Thread.CurrentThread.CurrentCulture.Name

Los posibles valores están definidos en el siguiente enlace, pero consta de una primera parte que es la cultura en letras minúsculas, un guión y el país en letras mayúsculas.
Aparte de un valor especifico de cultura como “es-ES”, “eu-ES”, etc., en la página existe una forma de indicar que sea la cultura predeterminada: “auto”, la cual es la que se define en el archivo de recursos por defecto (tema que se explica mas adelante).

[HowTo interrupted...]

Y por hoy ya vale, mañana más, que me ha pasado el manual en un .doc el muy gañan, y ponerlo aquí cuesta un pokiko. Que jesus, ¿has leido el mail? ¿te animas o no? jeje.