November 2009 - Artículos

El mal uso de var

Ultimamente vengo viendo mucho código en el que se hace intensivo el uso de var para declarar todo tipo de variables y me gustaría dar mi opinión sobre este mal uso:

El uso extensivo de var dificulta la legibilidad y comprensión del código fuente, porque un buen código (por lo menos para mí) es el que con leerlo lo podemos entender, por ejemplo:

var i = obj as string;

En este caso concreto se puede observar claramente que el tipo es string (porque lo vemos), pero y en esta caso:

var i = obj;

Pues en esa caso lo mejor podemos hacer es situarnos encima de obj y dejar que el VS nos ilumine con su sabiduría, o por ejemplo en este caso no sabemos que devuelve ese método:

var i = DAL.GetValor();

y no vale la excusa de que es cómodo y que hay clases que son muy largas de escribir, para eso está eso tenemos a Resharper y en su defecto al intellisense de VS :)

Mis 2 céntimos :)

Salu2

Publicado por Luis Ruiz Pavón | 7 comment(s)
Archivado en: ,,

[MOSS 2007] WebParts del tipo ErrorWebPart aparecen cuando usamos SPLimitedWebPartManager

El otro día desarrollando una feature para conectar webparts programáticamente (Escribiré algo sobre esto muy pronto) me encontré un pequeño problema a la hora de listar los webparts de un sitio usando la clase SPLimitedWebPartManager y era que los webparts de tipo ContentByQueryWebPart y los SummaryLink me los devolvía del tipo ErrorWebPart.

Esto se produce cuando ejecutamos el código en la feature receivers o en una aplicación cliente fuera de MOSS, porque probé el código en un webpart y funcionó. Esto me llevo a pensar que algo había que me estaba faltando y claro está que no disponemos en la feature y ni en la aplicación cliente del SPContext, al cual se accede desde dichos webparts para crear las url relativas de las tres hojas de estilo Xsl (MainStyle, HeaderStyle or ItemStyle).

Googleando encontré la solución a dicho problema que es crear un contexto falso:

if (HttpContext.Current == null)
{
    HttpRequest httpRequest = new HttpRequest(String.Empty, web.Url, String.Empty);
    HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new StringWriter()));
    HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
}

Sí os preguntáis como yo me pregunté por qué en el contexto mete el item HttpHandlerSPWeb, es por qué la clase SPContext en su propiedad estática Current, si vemos el código con reflector hace uso del método GetContextWeb de la clase SPControl:

public static SPContext Current
{
    get
    {
        SPContext context = null;
        if (HttpContext.Current == null)
        {
            return context;
        }
        while (SPControl.GetContextWeb(HttpContext.Current) != null)
        {
            try
            {
                context = GetContext(HttpContext.Current);
            }
            catch (FileNotFoundException)
            {
            }
            return context;
        }
        return null;
    }
}

Y sí miramos el código de SPControl.GetContextWeb():

public static SPWeb GetContextWeb(HttpContext context)
{
    return SPWebEnsureSPControl(context);
}
private static SPWeb SPWebEnsureSPControl(HttpContext context)
{
    SPWeb web = (SPWeb) context.Items["HttpHandlerSPWeb"];
    if (web == null)
    {
        if (context.User == null)
        {
            throw new InvalidOperationException();
        }
        if (SPSecurity.ImpersonatingSelf || (SPSecurity.UserToken != null))
        {
            throw new InvalidOperationException();
        }
        try
        {
            SPSite site;
            context.Items["HttpHandlerSPSite"] = site = new SPSite(SPFarm.Local, SPAlternateUrl.ContextUri, true);
            web = site.OpenWeb();
            context.Items["HttpHandlerSPWeb"] = web;
            SPRequestModule.InitContextWeb(context, web);
            if (!SPContext.GetShouldInitThreadCultureWhenContextWebIsInited(context))
            {
                return web;
            }
            web.SetThreadCultureAfterInit();
        }
        catch (FileNotFoundException)
        {
        }
    }
    return web;
}
 

Ahí podemos ver como sí no tenemos un contexto web y no tenemos el item HttpHandlerSPWeb obtendremos siempre este dichoso error.

Al final lo suyo es que liberemos el contexto:

HttpContext.Current = null;

 

Espero que os sirva, salu2!!!

[Tips] Crear nuestras propias directivas de compilación

Una entradita rápida para ser viernes. El otro día un compañero me dijo que sí sabía como se podían crear directivas de compilación para un tipo de configuración especifica como por ejemplo se hace con la directiva DEBUG:

#if DEBUG
 
Console.WriteLine("Debug");
 
#endif

Los pasos son los siguientes:

dcp

dcp2

image

Nos vamos a las propiedades del proyecto:

image

image

 

 

Una vez creada y configurada y guardada, nos vamos al editor de VS y con la configuración de Debug habilitada vemos que el texto está en gris, eso quiere decir que no estamos en la configuración adecuada para que se cumpla esa directiva de compilación:

 image

Cambiamos la configuración a MyConfiguration:

image

Y probamos:

image

Salu2 y buen finde

Publicado por Luis Ruiz Pavón | 5 comment(s)

[XmlSerializer] El atributo XmlInclude: Aplicando conceptos de POO en la serialización de las clases

Imaginaros que tenéis que almacenar información de los medios de transporte que dispone una empresa, como puede puede ser coches, barcos, aviónes… y dicha información ha de ser serializada en un fichero XML.  Cada entidad especifica como el coche o el avión tienen caracteristicas diferentes, un coche tiene marchas, cilindrada… mientras que un avión podría tener el número de motores que dispone… La pregunta es, ¿Como podemos serializar esta información, de manera que sí añadimos un nuevo medio de transporte, no tengamos que tocar nada de nuestro código de serialización, ni añadir nuevas colecciones ni propiedades a nuestra clases bases?, es decir, hacerlo de una manera genérica y no tener por cada tipo de transporte una lista que contenga objetos de ese tipo. Pues manos a la obra:

Lo primero será crear una clase abstracta que la llamaremos MedioTransporte, a la que añadiremos un a propiedad que tendrán en común que será la marca del transporte, ya que el tipo nos lo dará la propia entidad:

namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    [XmlRootAttribute("transporte")]
    [XmlInclude(typeof(Coche))]
    [XmlInclude(typeof(Avion))]
    public abstract class MedioTransporte
    {
        [XmlAttribute("marca")]
        public string Marca
        {
            get;
 
            set;
        }
    }
}

Ahora creamos 2 medios de transporte, Coche y Avion, que heredan de MedioTransporte:

namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    public class Coche : MedioTransporte
    {
        [XmlAttribute("cilindrada")]
        public int Cilindrada
        {
            get;
 
            set;
        }
 
        [XmlAttribute("marchas")]
        public int Marchas
        {
            get;
 
            set;
        }
    }
}
namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    public class Avion : MedioTransporte
    {
        [XmlAttribute("numeromotores")]
        public int NumeroMotores
        {
            get;
 
            set;
        }
    }
}

 

Y por supuesto, la clase general que es la Empresa:

namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    [XmlRootAttribute("empresa")]
    public class Empresa
    {
        [XmlAttribute("nombre")]
        public string Nombre
        {
            get;
 
            set;
        }
 
        [XmlArray("mediosdetransporte")]
        [XmlArrayItem("mediodetransporte")]
        public List<MedioTransporte> Transportes
        {
            get;
 
            set;
        }
    }
}

Creamos una aplicación de consolo para probar:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using Geeks.Serializer.Entities;
 
namespace Geeks.Serializer
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
 
            ns.Add(String.Empty, String.Empty);
 
            XmlSerializer serializer =
                new XmlSerializer(typeof(Empresa));
 
            Empresa empresa = new Empresa();
            empresa.Nombre = "Transportes Urgentes NET";
 
            empresa.Transportes = new List<MedioTransporte>();
 
            Coche coche = new Coche();
            coche.Marca = "Seat";
            coche.Cilindrada = 1200;
            coche.Marchas = 5;
 
            empresa.Transportes.Add(coche);
 
            Avion avion = new Avion();
            avion.Marca = "Airbus 380";
            avion.NumeroMotores = 4;
 
            empresa.Transportes.Add(avion);
 
            using (TextWriter writer = new StreamWriter(@"C:\temp\config.xml"))
            {
                serializer.Serialize(writer, empresa, ns);
            }
        }
    }
}

 

Ejecutamos y este es el resultado:

<empresa nombre="Transportes Urgentes NET">
  <mediosdetransporte>
    <mediodetransporte d3p1:type="Coche" 
                       marca="Seat" 
                       cilindrada="1200" 
                       marchas="5" 
                       xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
    <mediodetransporte d3p1:type="Avion" 
                       marca="Airbus 380" 
                       numeromotores="4" 
                       xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
  </mediosdetransporte>
</empresa>

¿Y donde está el truco para que salga el type de la entidad y la POO que se ha aplicado?

La POO la hemos aplicado al crear la clase abstracta MedioTransporte y heredar de ella en Coche y Avion, porque sino hacemos esto tendríamos que haber hecho algo como esto:

namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    [XmlRootAttribute("empresa")]
    public class Empresa
    {
        [XmlAttribute("nombre")]
        public string Nombre
        {
            get;
 
            set;
        }
 
        [XmlArray("coches")]
        [XmlArrayItem("coche")]
        public List<Coche> Coches
        {
            get;
 
            set;
        }
 
        [XmlArray("aviones")]
        [XmlArrayItem("aviones")]
        public List<Avion> Aviones
        {
            get;
 
            set;
        }
    }
}

 

Por cada nuevo medio de transporte, tenemos que estar añadiendo una nueva colección a la clase Empresa y además se serializará en un nuevo elemento, cosa que para mí queda bastante feo, además habría que estar tocando cada 2x3 la clase.

Y aquí es donde entra en juego el atributo XmlInclude, si añadimos un nuevo medio de transporte, solo necesitamos añadir un atributo nuevo a la clase MedioTransporte para que lo serialice, por ejemplo añadimos un Barco:

namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    public class Barco : MedioTransporte
    {
        [XmlAttribute("eslora")]
        public int Eslora
        {
            get;
 
            set;
        }
    }
}
namespace Geeks.Serializer.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
 
    [Serializable]
    [XmlRootAttribute("transporte")]
    [XmlInclude(typeof(Coche))]
    [XmlInclude(typeof(Avion))]
    [XmlInclude(typeof(Barco))]
    public abstract class MedioTransporte
    {
        [XmlAttribute("marca")]
        public string Marca
        {
            get;
 
            set;
        }
    }
}

Añadimos a la colección de Transportes un barco:

Barco barco = new Barco();
barco.Eslora = 24;
 
empresa.Transportes.Add(barco);

 

 

Y vemos el XML:

<?xml version="1.0" encoding="utf-8"?>
<empresa nombre="Transportes Urgentes NET">
  <mediosdetransporte>
    <mediodetransporte d3p1:type="Coche" 
                       marca="Seat" 
                       cilindrada="1200" 
                       marchas="5" 
                       xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
    <mediodetransporte d3p1:type="Avion" 
                       marca="Airbus 380" 
                       numeromotores="4" 
                       xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
    <mediodetransporte d3p1:type="Barco" 
                       eslora="24" 
                       xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" />
  </mediosdetransporte>
</empresa>

A mí me parece una solución bastante elegante.

Adjunto el código de ejemplo.

Salu2

Publicado por Luis Ruiz Pavón | 2 comment(s)
Archivado en: ,,,