domingo, 9 de noviembre de 2008
Sobre el casting ¿Carencia del compilador?
Bueno, seguro que cuando leáis este post lo primero que vais a pensar es "¿Qué hace el
friki este escribiendo un post un sábado a las 4 de la mañana? ¿No tiene nada mejor que hacer?"
Vale. Soy un frikazo ¿Y qué?
En fin, he estado dando vueltas a una cosa y quería comentarla con los máquinas de mis colegas de gremio.
No voy a entrar en el origen de mi problema. Voy a ir directamente a la esencia del mismo: Hacer casting entre clase padre e hija.
Voy a hacer un ejemplo que simplifica al máximo el problema.
Tenemos una clase base y una clase derivada.
public class BaseClass
{
private int property1;
public int Property1
{
get { return property1; }
set { property1 = value; }
}
}
public class DerivedClass : BaseClass
{
private int property2;
public int Property2
{
get { return property2; }
set { property2 = value; }
}
}
Vamos a ver todos los castings que podemos hacer.
De hija a base:
static void Main()
{
DerivedClass obj1 = new DerivedClass();
BaseClass obj2 = obj1;
}
Chupado. Como un objeto DerivedClass ya es un BaseClass, se puede hacer una conversión implítica.
De base a hija:
static void Main()
{
BaseClass obj1 = new DerivedClass();
DerivedClass obj2 = (DerivedClass) obj1;
}
Perfecto. Hacemos un casting de la clase base a la derivada. Es necesario hacer un casting explícito porque un objeto de la clase base no tiene por qué ser de la clase derivada. En nuestro caso sí lo es porque obj1 contiene un DerivedClass. No fallará ni en tiempo de complilación ni de ejecución. El compilador nos deja hacer esto sabiendo que nos arriesgamos a un petardazo en tiempo de ejecución, como ocurre en el siguiente ejemplo.
static void Main()
{
BaseClass obj1 = new BaseClass();
DerivedClass obj2 = (DerivedClass) obj1;
}
Compila pero da un petardazo lógico y normal en tiempo de ejecución. obj1 no contiene un DerivedClass.
En mi aplicación necesito hacer este casting. La solución es muy sencilla y a todos se nos ocurre enseguida. Haz un constructor de DerivedClass que reciba un BaseClass por parámetro. De esa forma la clase derivada queda así.
public class DerivedClass : BaseClass
{
public DerivedClass()
{
}
public DerivedClass(BaseClass parent)
{
this.Property1 = parent.Property1;
}
private int property2;
public int Property2
{
get { return property2; }
set { property2 = value; }
}
}
y el siguiente ejemplo funciona:
static void Main()
{
BaseClass obj1 = new BaseClass();
DerivedClass obj2 = new DerivedClass(obj1);
}
Hemos pasado de un objeto de la clase base a un objeto de la clase derivada.
Mi idea fue: Yo kiero ser más chulo y hacer eso con un casting (como el ejemplo que falla) en lugar de con el constructor. Pues me implemento un conversor propio (por ejemplo en la clase derivada) y a correr.
La clase derivada quedaría así:
public class DerivedClass : BaseClass
{
private int property2;
public int Property2
{
get { return property2; }
set { property2 = value; }
}
public static explicit operator DerivedClass(BaseClass parent)
{
DerivedClass result = new DerivedClass();
result.Property1 = parent.Property1;
}
}
Hago el conversor explícito en lugar de implícito para no ser demasiado chulo.
El código que lo prueba queda:
static void Main()
{
BaseClass obj1 = new BaseClass();
DerivedClass obj2 = (DerivedClass) obj1;
}
Pues bien. Esto, que a mi me parecía lógico, no compila. Da el siguiente error en la clase DerivedClass:
"user defined conversion to/from base class"
El número de error es CS0553
He investigado un poco y he visto la página de Microsoft donde está documentado el error. http://msdn.microsoft.com/en-us/library/031a701z(VS.80).aspx
Según ellos, no puedes hacerlo porque no lo necesitas.
Estamos de acuerdo en que no necesito un conversor propio para pasar de una clase hija a una clase padre, pero para pasar de una clase padre a una hija sí estaría bien. De hecho en el link que os he mandado hay un comentario de uno al que le pasa lo mismo que a mi.
Nadie le ha dado respuesta desde Microsoft...
Espero vuestros comentarios.
Saludos.
viernes, 7 de noviembre de 2008
Guía de arquitectura de aplicación - Release
Patterns & practices: App Arch Guide project http://www.codeplex.com/AppArch
martes, 4 de noviembre de 2008
¿Reinventar la rueda? No gracias
Me he decidido a escribir esta entrada a raíz de una investigación que he realizado recientemente previa al desarrollo de la web de un amigo mío. El caso es que es odontólogo y necesita (bueno yo se la voy a regalar por su cumpleaños) una web promocional para sus clínicas dentales.
Entonces me puse manos a la obra:
Abrir Visual Studio 2008 (por supuesto), New Project... Web Project... y despues de obtener el maravilloso "Empty Web Project" tuve el problema que tienen los escritores cuando se enfrentan a un folio en blanco, igualito. Decisiones sencillas como gestión de usuarios, perfiles, base de datos etc las tenía claras pero... Qué pereza empezar a desarrollar todo desde cero. Diseña la Master, estructura de la web... Realmente me gustaría saber cuánto tiempo se pierden actualmente en los proyectos, nuestros proyectos, en desarrollar módulos que ya están desarrollados. Un sabio profesor de universidad me dijo, puede haber un mismo trabajo de Ingeniería en un desarrollo a medida con un I+D impresionante, como en un análisis de mercado analizando herramientas existentes que puedan cubrir mis necesidades.
Entonces me vino a la cabeza la pregunta clave: ¿No abrá algún proyecto en el que me pueda basar, con una estructura válida que pueda utilizar, con gran parte del trabajo tedioso hecho? Pues afortunadamente la respuesta final es que sí.
Encontré los Starter Kits and Community Projects.
Nos encontramos una veriedad generosa de proyectos 'base', tales como foros, webs de anuncios, webs para comunidades y muchos mas. Algunos mediante Instaladores de Contenido para Visual Studio, otros con proyectos ya desarrollados que tendremos que abrir nosotros, copiandolos en local.
Este elenco de proyectos OpenSource nos proporcionan una estupenda base para poder empezar con un esqueleto ya realizado, ideal para vagos (como yo).
De todas formas, estos proyectos contienen detalles muy interesantes en su interior. Seguro que os sorprende a más de uno la estructura de algunos proyectos y la utilización de controles base del Framework. Que sí, que a todos se nos llena la boca diciendo las maravillas del FrameWork, que si es potentisimo, que si nos ahorra mucho trabajo, que si tal que si cual... pero la gestión de perfiles y usuarios nos la hacemos nosotros, en vez de utilizar la potente gestión del propio FrameWork xej. Ya se que esto es aplicable en función de necesidades del proyecto, pero ya me entendéis. En estos proyectos encontraréis 100% exprimidos los controles Web del FrameWork, y en muchos casos sorprende la funcionalidad conseguida en función de las líneas de código implementadas.
Bueno os animo a que le dediquéis un ratejo para investigar lo que os podéis encontrar, pero os adelanto algo:
Classifieds Site Starter Kit:
Base de un proyecto web para clasificados (anuncios que perduran un tiempo x)
Job Site Starter Kit:
Base para un proyecto web para trabajos (empresas vs empleados)
Kigg Starter Kit:
Base para un proyecto web estilo Digg
Y bueno, muchos mas en http://www.asp.net/community/projects/
jueves, 30 de octubre de 2008
Métodos opcionales en las propiedades
La principal funcionalidad que obtendremos al implementar el método Reset es que aparecerá una indicación visual en el explorador de propiedades con la posibilidad de restablecer el valor predeterminado para la misma. El mismo resultado se consigue con la utilización del atributo DefaultValue como marcador de la propiedad pero su uso está restringido a tipos de datos simples.
Con el método ShouldSerialize obtendremos una serialización de la propiedad condicionada a la expresión que evaluemos en el cuerpo del mismo. Este método será invocado por el runtime durante la serialización de la clase.
Veamos un ejemplo de estos dos métodos:
.....
private Negocio tiendaMuebles = null;
public Negocio TiendaMuebles
{
get { return this.tiendaMuebles; }
set { this.tiendaMuebles = value; }
}
public bool ShouldSerializeTiendaMuebles()
{
return this.tiendaMuebles != null;
}
public void ResetTiendaMuebles()
{
this.tiendaMuebles = null;
}
....
Un saludo.
miércoles, 29 de octubre de 2008
Application Architecture Guide 2.0 Beta
Leo en Geeks que han publicado una versión preliminar de Application Architecture Guide 2.0. (por ahora solo versión en Inglés).
Es un pdf que se puede descargar y es muy interesante ya que estamos sumergidos en algo parecido.
A mandar!
lunes, 27 de octubre de 2008
VS no me pide credenciales al conectar con TFS :(
Voy a empezar con algo light. Espero que no demasiado...
Como adelantaba en el anterior post, vamos a dar solución a una cosa muy tonta pero que nos puede dar muchos quebraderos de cabeza. Seguro que muchos ya lo sabéis y algunos también lo habéis leido por el anterior método arcaico (correo a todos los que te acuerdas).
A todos nos ha pasado alguna vez que queremos conectar a nuestro TFS con Visual Studio, a traves de Team Explorer, con una cuenta diferente a la habitual, por ejemplo TFSSETUP. Resulta que algún día marcamos el check de recordar contraseña y a partir de ahí no podemos hacer que VS nos la pida otra vez.
La pregunra es: ¿Dónde almacena Visual Studio esas credenciales?
Bien, las credenciales no las cachea Visual Studio sino el sistema operativo. De hecho el problema nos puede aparecer con cualquier otro producto, aunque seguramente el que más nos molesta sea el acceso a TFS.
Para limpiar estas credenciales guardadas debemos seguir los siguientes pasos.
Tenemos dos opciones, dependiendo de cómo esté sonfigurado nuestro sistema operativo:
- Modo XP "molón". Este es el modo que nos muestra las cosas como si supiéramos.
- En el panel de control seleccionar la vista clásica. Después entramos en Cuentas de usuario.
- En la ventana de cuentas de usuario vamos a la pestaña de opciones avanzadas.
- En la ventana que nos sale nos aparece una lista con las credenciales que tenemos para acceder a los distintos servidores. En el ejemplo sólo hay credenciales guardadas para un servidor que se llama mts. Si accedeis por IP en lugar de por nombre , aquí aparecerá la IP del servidor.
- En esa pantalla eliminamos la entrada que nos interese, reiniciamos VS (o la aplicación que sea) y nos debe pedir las credenciales de nuevo.
- Modo XP "nenaza". Sí, ese modo feo con el que suelen venir nuestros equipos corporativos recien plataformados, antes de meterlos en el dominio. Es como todo más fácil pero no hay cristiano que encuentre dónde están las cosas.
- Igual que en el modo anterior (Panel de control --> Cuentas de usuario)
- Elegimos cambiar una cuenta.
- Elegimos la cuenta a cambiar
- Una vez en tenemos la cuenta para cambiar, pinchamos en Administrar mis contraseñas de red.
- A partir de aquí, todo igual que en el modo anterior.
Y eso es todo.
Sé que este post puede ser interpretado como un insulto a vuestra inteligencia (sobre todo por los pantallazos en plan "es la primera vez que enciendo un ordenador"). Os prometo que los siguientes posts serán más interesantes.
Vamos a ver si entre todos sacamos adelante esta iniciativa que, personalmente, me parece perfecta.
Saltar Validación de Certificado en una Conexión SSL
El problema viene cuando el certificado utilizado en el servidor de desarrollo para establecer SSL está revocado, caducado, con un DN de prueba etc... Al intentar realizar la conexión al equipo remoto por HTTPS notaremos como nos es imposible ya que el mismo framework nos denegará el acceso.
Podemos comprobar que la conexión no es de confianza si lanzamos un IE y obtenemos un warning indicandonos que la conexión es inválida debido a defectos en el certificado. El navegador nos permitirá omitir este error y proseguir pero... Cómo omitimos esta validación desde código??
Bien, solo tenemos que suscribirnos al evento de validación del certificado en local, y generosamente, permitir la conexión para cualquier certificado siguiendo el siguiente ejemplo (Importante: Este ejemplo es válido para FrameWork 2.0 en adelante)
Previo a la llamada:
// Creamos un delegado para aprobar el certificado cuando se realize la peticion
RemoteCertificateValidationCallback remoteCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
//Lo asignamos a la llamada de vuelta
ServicePointManager.ServerCertificateValidationCallback += remoteCallback;
Y en el procedimiento de validacion
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
//Validamos el certificado
return true;
}
Bueno, espero solucione muchas depuraciones ;)
Compartir tipos entre Servicios.
En este nuevo número vamos a ver un problema muy muy común cuando trabajamos con arquitecturas SOA o intentamos hacerlo (como es mi caso). Seguro que vamos a tener diferentes servicios y seguro que varios de esos servicios van a utilizar tipos comunes. El problema es que cuando importamos estos servicios en el cliente se nos generan dos tipos (no compatibles) para el mismo tipo compartido.
En primer lugar vamos a suponer que los servicios son implementados como Web Services (asmx).
Para solucionarlo hay que hacer dos cosas:
- Conseguir que los WSDL presenten exactamente la misma serialización para el tipo común. Para ello tenemos que especificar el tipo XML de nuestra clase. Debemos poner un namespace a nuestro tipo común. Ésto, unido a que el nombre del tipo y los campos van a serializar siempre igual, hará que ambos WSDLs definan el tipo común de igual forma.
- Decirle a nuestro gran generador de proxies que sea un poco cuidadoso y si detecta dos tipos iguales (namespace, nombre de tipo y esquema) que sólo genere una clase).
De esta forma generamos un único tipo en el cliente. Nos olvidamos de problemas de castings entre tipos (que eran iguales pero distintos) y de no poder pasar a un servicio los tipos que me devolvía otro. Vale... Pero ¿Cómo se hace? En este link nos explican cómo dar los dos pasos: http://msdn.microsoft.com/en-us/library/aa480505.aspx En este otro nos explican cómo dar el segundo paso más fácil. http://quickstarts.asp.net/QuickStartv20/webservices/doc/TypeSharing.aspx
Y en WCF??
Así --> http://geeks.ms/blogs/jlsoria/archive/2008/07/16/wcf-compartici-243-n-de-tipos-entre-referencias-a-servicios.aspx
Ahora os cuento mi vida. Como todos sabéis, estoy currando con Flex y ya van varias veces que me está condicionando en cosas muy importantes. Varios ejemplos son las entregas anteriores:
Aunque Flex (action script) define enumeraciones, los esquemas xsd también, por tanto WSDL también. Resulta que el generador de proxies tiene un bug y no funcionan (documentado por Adobe y sin workarround ni miras de que vayan a solucionarlo). Esto me ha obligado a no usar enumeraciones --> bajoncete
Aunque el protocolo SOAP define soap faults para transportar errores, y es así como se transportan las excepciones. Flex "descarta" la información que tú pasas en el soap fault y siempre manda la misma excepción genérica al proxy que ha generado. Entonces, nunca puedes ver nada de la excepción --> no puedes usar excepciones para comunicar errores (Documentado por Abobe y el WorkArround es "No uses excepciones") --> bajonazo!!
Ahora, cómo no, he encontrado aquí http://bugs.adobe.com/jira/browse/FB-1251 que no es capaz de darse cuenta de que hay un tipo común entre dos servicios. Dice que hay un workarround aunque no asegura que siempre vaya a funcionar. Ya he perdido mucho tiempo en el proyecto por temas como este. Mi problema actual es que tengo que hacer un servicio bastante más grande de lo que me gustaría (unión de dos), aunque la aplicación no es muy grande y el servicio tampoco es exagerado. A estas alturas no estoy a tiempo de cambiarlo y arriesgarme. Si algún alma caritativa tiene alguna idea o amigo de Flex (me consta que miguelín sí lo tiene ;) ) agradecería su ayuda eternamente.En la siguiente entrega hablaremos de dónde se puede limpiar el almacenamiento de contraseñas responsable que, por ejemplo, no se nos pida nunca la contraseña cuando accedemos al TFS. Es un coñazo cuando queremos cambiar la cuenta con que accedemos.
Un saludo a todos.
Mario.