jeudi 1 avril 2010

Asp.net 3.5 - Classe générique et DropDownList

Le remplissage des DropDownList est une opération basique que l'on peut être amené à réaliser souvent lorsque l'on traite des interfaces utilisateurs. Quand on y regarde de plus prés, ce sont toujours les même opérations qui reviennent, surtout lorsque l’on n’utilise pas une datasource.
 
La petite classe suivante est un exemple de ce que l'on peut faire avec une classe générique pour répondre à ce genre de besoin et factoriser son code.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Reflection;
 
public class DropDownListHelper<T>
{
    /// <summary>
    /// Constructeur
    /// </summary>
    public DropDownListHelper()
    {
        //Do nothing
    }
 
    /// <summary>
    /// Remplis une Ddl avec le contenue d'une liste
    /// </summary>
    /// <param name="Ddl">La Dropdown</param>
    /// <param name="Lst">La liste d'objet</param>
    /// <remarks>Le label sera la propriété de type String de l'objet, la Value sera la prorpiété de Type Int. Il est possible ne fournir que le Label ou que la Value</remarks>
    public static void FillDdl(DropDownList Ddl, List<T> Lst)
    {
        FillDdl(Ddl, Lst,true);
    }
 
    /// <summary>
    /// Remplis une Ddl avec le contenue d'une liste
    /// </summary>
    /// <param name="Ddl">La Dropdown</param>
    /// <param name="Lst">La liste d'objet</param>
    /// <param name="MustClean">Si True alors le contenue de la Ddl sera vidé avant d'ajouter les objets</param>
    /// <remarks>Le label sera la propriété de type String de l'objet, la Value sera la prorpiété de Type Int. Il est possible ne fournir que le Label ou que la Value</remarks>
    public static void FillDdl(DropDownList Ddl, List<T> Lst,Boolean MustClean)
    {
        string PropLibelle = string.Empty;
        string PropValue = string.Empty;
        Boolean HaveLibelle = false;
        Boolean HaveValue = false;
 
        var LstProperties = typeof(T).GetProperties();
 
 
        //Detection automatique des libellés et valeurs
        foreach (PropertyInfo prop in typeof(T).GetProperties())
        {
            //Libellé
            if (prop.PropertyType.Equals(typeof(String)))
            {
                if (!HaveLibelle)
                {
                    PropLibelle = prop.Name;
                    HaveLibelle = true;
                }
                else
                {
                    throw new InvalidPropertiesException("Plusieurs libellé possible,ne fournir qu'une seul propriété de type string");
                }
            }
            //Valeur
            if (prop.PropertyType.Equals(typeof(Int32)))
            {
                if (!HaveValue)
                {
                    PropValue = prop.Name;
                    HaveValue = true;
                }
                else
                {
                    throw new InvalidPropertiesException("Plusieurs Values possible,ne fournir qu'une seul propriété de type int");
                }
            }
        }
 
        if(!HaveValue && !HaveLibelle)
            throw new InvalidPropertiesException("Aucune propriété de type String ou Int trouvées");
        if (!HaveValue)
            PropValue = PropLibelle;
        if (!HaveLibelle)
            PropLibelle = PropValue;
 
        FillDdl(Ddl, Lst, PropLibelle, PropValue, MustClean);
    }
    /// <summary>
    /// Remplis une Ddl avec le contenue d'une liste
    /// </summary>
    /// <param name="Ddl">La Dropdown</param>
    /// <param name="Lst">La liste d'objet</param>
    /// <param name="Libelle">Le nom de la propriété contenant le Label</param>
    /// <param name="Valeur">Le nom de la propriété contenant la valeur</param>
    /// <param name="MustClean">Si True alors le contenue de la Ddl sera vidé avant d'ajouter les objets</param>
    public static void FillDdl(DropDownList Ddl,List<T> Lst,String Libelle, String Valeur,Boolean MustClean)
    {
        if (MustClean)
            ResetDDL(Ddl);
       
        foreach (T val in Lst)
        {
           
            PropertyInfo Lib =  typeof(T).GetProperty(Libelle);
            PropertyInfo Vals = typeof(T).GetProperty(Valeur);
            if (Lib != null && Lib.CanRead && Vals != null && Vals.CanRead)
            {
                string propLibelle = Lib.GetValue(val, null).ToString();
                string propValeur = Vals.GetValue(val, null).ToString();
                Ddl.Items.Add(new ListItem(propLibelle, propValeur.ToString()));
            }
        }
        Ddl.Items.Insert(0, new ListItem(string.Empty, "-1"));      
    }
 
 
 
 
    /// <summary>
    /// Vide une DDL passé en paramètres
    /// </summary>
    private static void ResetDDL(DropDownList val)
    {
        int cpt = val.Items.Count;
        for (int i = 0; i < cpt; i++)
            val.Items.RemoveAt(0);
    }
 
 
}
 
[Serializable()]
public class InvalidPropertiesException : System.Exception
{
    public InvalidPropertiesException() { }
    public InvalidPropertiesException(string message) { }
    public InvalidPropertiesException(string message, System.Exception inner) { }
 
    // Constructor needed for serialization
    // when exception propagates from a remoting server to the client.
    protected InvalidPropertiesException(System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) { }
}

Asp.net 3.5 - PostBack,FileUpload et serialisation

Après chaque postback le contenu du composant FileUpload est perdu si  on ne l’exploite pas. Il peut arriver des cas où l’on a besoin de le conserver sans forcément le sauvegarder sur disque.
Pour ces situations, j’utilise un objet SessionHttpPostedFile, reprenant les même possiblités qu’un HttpPostedFile et que j’ai rendu sérializable.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
 
/// <summary>
/// Equivalent Serializable d'un httpPostedFile, permet entre autre son stockage en session
/// </summary>
[Serializable]
public class SessionHttpPostedFile
{
 
    private byte[] BytePostedFile;
    [NonSerialized]
    private Stream TmpStream;
 
    /// <summary>
    /// Constructeur
    /// </summary>
    public SessionHttpPostedFile()
    {
        TmpStream = new MemoryStream();
        ContentLength = 0;
        ContentType = string.Empty;
        FileName = string.Empty;
    }
 
    /// <summary>
    /// Taille du fichier en Byte
    /// </summary>
    public int ContentLength { get; set; }
   
    /// <summary>
    /// Type Mime du fichier
    /// </summary>
    public string ContentType { get; set; }
 
    /// <summary>
    /// Nom du fichier
    /// </summary>
    public string FileName { get; set; }
   
    /// <summary>
    /// InputStream du fichier
    /// </summary>
    public Stream InputStream
    {
        get
        {
 
            if ((TmpStream == null || TmpStream.Length < 1) && BytePostedFile != null)
            {
                TmpStream = new MemoryStream();
                TmpStream.Write(BytePostedFile, 0, BytePostedFile.Length);
            }
            return TmpStream;
        }
        set {
            TmpStream = value;
            BytePostedFile = ReadToEnd(TmpStream);
        }
    }
 
    /// <summary>
    /// Sauvegarde le stream à l'emplacement voulu
    /// </summary>
    /// <param name="SaveFilename"></param>
    public void SaveAs(string SaveFilename)
    {
        try
        {
            var f = File.Create(SaveFilename);
            f.Close();
            File.WriteAllBytes(SaveFilename, BytePostedFile);
        }
        catch { }
 
      
    }
 
 
 
    /// <summary>
    /// Converti un stream en Byte[]
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    private  byte[] ReadToEnd(System.IO.Stream stream)
    {
        long originalPosition = stream.Position;
        stream.Position = 0;
        try
        {
            byte[] readBuffer = new byte[4096];
            int totalBytesRead = 0; int bytesRead;
            while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
            {
                totalBytesRead += bytesRead;
                if (totalBytesRead == readBuffer.Length)
                {
                    int nextByte = stream.ReadByte();
                    if (nextByte != -1)
                    {
                        byte[] temp = new byte[readBuffer.Length * 2];
                        Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                        Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                        readBuffer = temp; totalBytesRead++;
                    }
                }
            }
            byte[] buffer = readBuffer; if (readBuffer.Length != totalBytesRead) { buffer = new byte[totalBytesRead]; Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); } return buffer;
        }
        finally { stream.Position = originalPosition; }
    }
}