lundi 9 juin 2008

MgmtClassGen

Il y'a vraiment quelque chose d'énervant à découvrir un outils pratique qui se trouvait devant notre nez depuis toujours et qu'on a cherché si longuement. MgmtClassGen en fait partie, c'est un des outils de Visual Studio qui permet de générer des classes 'wrapper' fortements typées des objets WMI utilisables depuis le namespace System.Management.

C'est donc en tombant sur cet article :
http://blogs.msdn.com/saveenr/archive/2005/11/18/494366.aspx
que je me suis rendu compte qu'on devrait en préambule au développement sous visual studio, prendre connaissance des quelques outils qui l'accompagne.
http://msdn.microsoft.com/fr-fr/library/d9kh6s92.aspx

l'utilisation est on ne peux plus simple :
La commande "mgmtclassgen.exe Win32_Printer" génére le fichier Printer.CS qui contient une classe très bien commentée permettant d'utiliser l'objet WMI sous-jacent.

Pour celui qui savait déjà rien de neuf, pour moi ce fut une révolution.

mercredi 4 juin 2008

Implémentation d'un objet de gestion d'une transaction sur les fichiers

Implémentation de FileTransaction, un objet simple de sauvegarde et de restauration des fichiers sur lesquels on travail.

/// <summary>
///
Se charge du backup et de la restauration des fichiers qui sont ajoute9 e0 sa Gestion.
/// ne sauvegarde pas 2 fois le meame fichier.
/// </summary>
public class FileTransaction : IDisposable
{
const string DELETE_FILE_MAP = "DELETE";
string BackupFolder;

#region Constructeurs
/// <summary>
///
En utilisant ce constructeur c'est un re9pertoire alle9atoire qui est utilise9 pour la sauvegarde
/// </summary>
public FileTransaction()
: this(
Path.Combine(
Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Machine),
Path.GetRandomFileName()
)
) { }
/// <summary>
/// </summary>
/// <param name="backupFolder">
Spe9cifie le re9pertoire qui sera utilise9 pour les sauvegardes</param>
public FileTransaction(string backupFolder)
{
if (Directory.Exists(backupFolder)) Directory.Delete(backupFolder, true);
BackupFolder = Directory.CreateDirectory(backupFolder).FullName;
}
#endregion

private readonly
Dictionary<String, String> File_Map = new Dictionary<string, string>();

#region Ajout de fichier e0 la transaction
/// <summary>
///
Ajoute une liste de fichier e0 la transaction
/// </summary>
/// <param name="files"></param>
public void AddFiles(IEnumerable<String> files)
{
foreach (string file in files) AddFile(file);
}

/// <summary>
///
Ajout un fichier e0 la transaction
/// </summary>
/// <param name="file">
Chemin du fichier (relatif ou absolu)</param>
public void AddFile(string file)
{
string saved_file = Path.GetFullPath(file);
// Pas 2 fois le meame fichier quand meame !
if (File_Map.ContainsKey(saved_file)) return;

if (!File.Exists(saved_file))
{
// En cas de RollBack on supprimera le fichier
File_Map.Add(saved_file, DELETE_FILE_MAP);
}
else
{
string renamed_backup_filename = Path.GetFileName(saved_file) + "." + Path.GetRandomFileName();
string backup_file = Path.Combine(BackupFolder, renamed_backup_filename);

// On s'assure que le re9pertoire de copie existe
Directory.CreateDirectory(Path.GetDirectoryName(backup_file));

// c'est parti
File.Copy(saved_file, backup_file);
File_Map.Add(saved_file, backup_file);
}
}
#endregion

#region
Commit
/// <summary>
///
Efface la transaction et la possibilite9 de RollBack
/// </summary>
public void Commit() { Commit(true); }
public void Commit(bool destroyBackup)
{
Clear_File_Map();
if (destroyBackup) DestroyBackup();
}
#endregion

#region
RollBack
/// <summary>
///
Remet tous les fichier sauvegarde9 e0 leur place d'origine
/// </summary>
public void RollBack() { RollBack(true); }
public void RollBack(bool destroyBackup)
{
RestoreFiles();
Clear_File_Map();
if (destroyBackup) DestroyBackup();
}
#endregion

#region
Me9thodes prive9es
void Clear_File_Map()
{
File_Map.Clear();
}

void RestoreFiles()
{
foreach (string file in this.File_Map.Keys)
{
string backup = File_Map[file];

if (backup == DELETE_FILE_MAP)
{
if (File.Exists(file)) File.Delete(file);
}
else
{
string dir = Path.GetDirectoryName(file);
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
File.Copy(backup, file, true);
}
}
}

void DestroyBackup() { DestroyBackup(this.BackupFolder); }
void DestroyBackup(string backupFolder)
{
if (Directory.Exists(backupFolder)) Directory.Delete(backupFolder, true);
}
#endregion

#region
IDisposable Membres

public void Dispose()
{
if (File_Map.Count != 0) RollBack();
else Clear_File_Map();
}

#endregion
}


Utilisation :

FileTransaction FT = new FileTransaction();
String filename = "MonFichierSuperImportant.dat";
FT.AddFile(filename);
File.Delete(filename);
FT.RollBack();
// le fichier est restauré


Autre utilisation :

using (FileTransaction FT = new FileTransaction())
{
try
{
FT.AddFiles(new string[]{
"fichier1.txt",
"fichier2.txt",
"fichier3.txt"
});

// Traitement atomique : tout ou rien

// Helas quelque chose tourne mal
throw new Exception("TEST");

FT.Commit();
}
catch (Exception ex)
{
FT.RollBack();
}
}


FileTransaction implémente IDispose, ce qui lui donne des possibilités de restauration des fichiers en cas de destruction de l'objet avant le Commit.

string TestFile = "Mon fichier";
using (FileTransaction FT = new FileTransaction())
{
FT.AddFile(TestFile);
File.Delete(TestFile);
}// Dispose ;-)


Ici le fichier est restauré à la fin du using, automatiquement.

Yin Yang Xaml

<Grid>
<
Path Style="{DynamicResource Yin}">
<
Path.Data>
<
PathGeometry>
<
PathGeometry.Figures>
<
PathFigure StartPoint="100,0" IsClosed="False">
<
ArcSegment Point="100,100" Size="25,25" SweepDirection="Clockwise" />
<
ArcSegment Point="100,200" Size="25,25" SweepDirection="Counterclockwise" />
<
ArcSegment Point="100,0" Size="50,50" SweepDirection="Clockwise" />
</
PathFigure>
</
PathGeometry.Figures>
</
PathGeometry>
</
Path.Data>
</
Path>
<
Path Style="{DynamicResource Yang}">
<
Path.Data>
<
PathGeometry>
<
PathGeometry.Figures>
<
PathFigure StartPoint="100,200" IsClosed="False">
<
ArcSegment Point="100,100" Size="25,25" SweepDirection="Clockwise"/>
<
ArcSegment Point="100,0" Size="25,25" SweepDirection="Counterclockwise" />
<
ArcSegment Point="100,200" Size="50,50" SweepDirection="Clockwise" />
</
PathFigure>
</
PathGeometry.Figures>
</
PathGeometry>
</
Path.Data>
</
Path>
<
Path Style="{DynamicResource Yin}">
<
Path.Data>
<
PathGeometry>
<
PathGeometry.Figures>
<
PathFigure StartPoint="100,150" IsClosed="False">
<
ArcSegment Point="100,149" Size="15,15" IsLargeArc="True" SweepDirection="Clockwise" />
</
PathFigure>
</
PathGeometry.Figures>
</
PathGeometry>
</
Path.Data>
</
Path>
<
Path Style="{DynamicResource Yang}">
<
Path.Data>
<
PathGeometry>
<
PathGeometry.Figures>
<
PathFigure StartPoint="100,50" IsClosed="False">
<
ArcSegment Point="100,51" Size="15,15" IsLargeArc="True" SweepDirection="Clockwise" />
</
PathFigure>
</
PathGeometry.Figures>
</
PathGeometry>
</
Path.Data>
</
Path>
</
Grid>

Sans commentaires ....