Compilation et appel de code C# dans un System.String au runtime
janvier 28th, 2012 § Laisser un commentaire
Voici un petit bout de code vous permettant de compiler du code sous forme de string et d’instancier des objets. Pour éviter d’écrire du code d’appel par réflexion, ma classe a générer implémente une interface que j’utiliserai ensuite manipuler le resultant de CreateObjectFromAssembly. Seul la construction de l’objet se fait par réflexion.
/// <summary>
/// Produces new assembly at runtime.
/// </summary>
/// <param name="references">The assembly references.</param>
/// <param name="sourceCode">The source code to compile.</param>
/// <param name="outputAssemblyName">Output dll name.</param>
/// <returns>Compilation result</returns>
private CompilerResults ProduceAssembly(string[] references,
string sourceCode,
string outputAssemblyName)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler codeCompiler = codeProvider.CreateCompiler();
CompilerParameters compilerParameters =
new CompilerParameters(references,
outputAssemblyName);
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = false;
return codeCompiler.CompileAssemblyFromSource(compilerParameters,
sourceCode);
}
/// <summary>
/// Creates new object from dynamicaly loaded assembly
/// </summary>
/// <param name="AssemblyName">Name of the assembly to load.</param>
/// <param name="className">Name of the class to instanciate.</param>
/// <param name="constructorParameters">The constructor parameters.</param>
private bool CreateObjectFromAssembly(string AssemblyName,
string className,
object[] constructorParameters,
out object createdObject)
{
object tmp = createdObject = null;
Assembly myAssembly = Assembly.LoadFrom(AssemblyName);
Module[] myModules = myAssembly.GetModules();
myModules.Where(module => module.Name == AssemblyName)
.Select(module => module.GetTypes())
.ToList()
.ForEach
(
t => t.Where(types => types.Name == className)
.ToList()
.ForEach(
type => tmp = Activator.CreateInstance(type,
constructorParameters))
);
createdObject = tmp;
return createdObject != null;
}
Pastebin : http://pastebin.com/S6fpYcXD
Crystal Report 2011 : CrystalDecisions.Shared.SharedUtils Exception
janvier 4th, 2012 § Laisser un commentaire
Always on top window
janvier 4th, 2012 § Laisser un commentaire
Un petit bout d’interop pour créer des TopMost window. Les flags permettent d’éviter a la fenêtre de se resizer et de bouger après l’appel de la fonction. (Sinon, avec les arguments {x,y,cx,cy} à 0, la fenêtre fera 0*0 à la coordonnée 0:0).
Ensuite le placement de la fenêtre se fait avec le IntPtr HWND_x.
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 FLAGS = SWP_NOMOVE | SWP_NOSIZE;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public void SetOnTop()
{
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, FLAGS);
}
public void UnSetOnTop()
{
SetWindowPos(this.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS);
}
Ref. : msdn
Quick Setup de Log4Net en C#
décembre 13th, 2011 § Laisser un commentaire
Bonjour, un petit tuto’ sur comment utiliser basiquement log4net dans vos applications suite à une demande par mail.
Tout d’abord un petit exemple de Log4Net :
static void Main(string[] args)
{
log4net.ILog log = LogManager.GetLogger(typeof(Program));
log4net.Config.BasicConfigurator.Configure();
log.Debug("I'm debuging this app");
log.Info("Cause i need more information");
log.Warn("About the compilation warning");
log.Error("Due to a developper error");
log.Fatal("And create fatal exceptions :)");
Console.ReadLine();
}
La sortie :
DEBUG2011-12-13 09:12:09 – I'm debuging this app INFO 2011-12-13 09:12:09 – Cause i need more information WARN 2011-12-13 09:12:09 – About the compilation warning ERROR2011-12-13 09:12:09 – Due to a developper error FATAL2011-12-13 09:12:09 – And create fatal exceptions :)
Le code parle de lui même.
Téléchargez les bin’s a l’adresse : http://logging.apache.org/log4net/download.html
Décompressé ça peut paraitre gros pour du log (30Mo) mais c’est parce qu’il y a les DLL pour tous les framework et subset de dotnet + la documentation XML. Pour une DLL de 300Ko, 1.5Mo de docs xml. La librairie finale ne fait que 250/300Ko.
Une autre solution consiste aussi à utiliser NuGet pour les paquets. C’est à vous de voir.
Ensuite, comme d’habitude, on rajoute une référence.
Ceci fait on vas éditer (ou créer) un fichier .config (Web.config ou App.config, selon le scénario) et y rajouter les nodes suivants :
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\log.txt"/>
<param name="AppendToFile" value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n"/>
</layout>
</appender>
</log4net>
<startup>
</configuration>
Pour le moment il log dans la console a cause du basic configurator. Pour lui dire d’aller jeter un œil dans les .config il suffit de rajouter :
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Ensuite, on supprime la ligne 4 de l’exemple (le basic configurator) et on obtiens une instance de ILog que nous utiliserons dans notre application.
Quelques issues rencontrés
- Si il gueule pour System.Web, passez le target de dotnet 4 client profile à dotnet 4 dans la configuration du projet.
- Si vous n’arrivez pas a écrire, vérifiez les permissions sur le filesystem.
- Pour le reste, RTFM
Apache Log4net manual
Et au passage…
Convertir VHD en VMDK
novembre 29th, 2011 § Laisser un commentaire
Bonjour, en attendant la publications des gros articles dans le pipe (cfr. tweet) un petit “tips” pour convertir des virtual machine Hyper-V et plus globalement des fichiers VHD en VMDK pour les charger dans VmWare Workstation. Après des essais infructueux avec VmWare vCenter Converter, qui reste un très bon outil gratuit de conversion de VM notamment pour pomper une machine physique vers une VM, j’ai testé l’outil WinImage qui a donné de très bon résultats, sauf en terme de compression de donnée (on ne peut pas tout avoir).
L’outil est en shareware 30 jours : Cliquez ici pour l’obtenir
1. L’outil installé et lancé, allez dans Disk -> Convert Virtual Hard Disk Image. Une fenêtre d’exploration s’ouvre, allez sélectionner le VHD à convertir.

2. Un fois le VHD sélectionner vous avez le choix entre un disque à taille fixe ou un disque dynamique. Pour rappel, si on a un disque de 100Go rempli a 50% (donc 50Go) :
- Fixed : Fichier de 100Go sur le disque mais gain en performance, moins de fragmentation coté hôte, mais consomme plus de place.
- Dynamic : Fichier de 50Go mais perte de performance et augmente le taux de fragmentation du fichier, mais consomme moin de place.
Pour ma part je m’oriente plus souvent vers du fixed

3. Ensuite, un nouvelle boite d’exploration, n’oubliez pas de préciser le type de fichier cible (vmdk) car le choix par defaut est vhd.
4. Enfin, il n’y a plus qu’a attendre que la conversion soit finie.
J’ai converti un VHD de 150Go sur un 10 000k/rpm en 1H +/-. (sur ce type d’actions c’est le HDD qui fait goulot d’étranglement)
A bientôt pour les articles sur FxCop et l’écriture de règles, Microsft Common Compiler Infrastructure, la création de custom template dans visual studio et pleins d’autres choses
Désactiver l’hebergement automatique des library de services WCF
novembre 15th, 2011 § Laisser un commentaire
Cette feature serait apparament en backlog pour la prochaine release/update? de visual studio si on s’en tiens a : http://connectbeta.microsoft.com/VisualStudio/feedback/details/533316/cannot-disable-wcf-service-host
Mais pour le supprimer le seul moyen est d’aller supprimer le ProjectTypeGUID et le ProjectExtensions dans le fichier .csproj de la lib. Le GUID est 3D9AD99F-2412-4246-B90B-4EAA41C64699.
Il faut donc le supprimer de :
<ProjectTypeGuids>{3D9AD99F-2412-4246-B90B-4EAA41C64699};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
Et supprimer la section suivante dans la fin du fichier :
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{3D9AD99F-2412-4246-B90B-4EAA41C64699}">
<WcfProjectProperties>
<AutoStart>True</AutoStart>
</WcfProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
Twitter, OAuth & LinqToTwitter for dummies
octobre 19th, 2011 § Laisser un commentaire
Un petit post qui explique basiquement comment fonctionne l’authentification d’une application twitter.
Le souci très vite rencontré c’est OAuth. Tout comme OData et tous les Oxxx, la documentation est hyper fournie, voir trop fournie… ce qui fait que l’on perd vite pied dans des détails techniques. Ce que je propose ici ce n’est pas de savoir comment fonctionne OAuth et twitter mais de savoir pratiquement comment authentifier son appli.
Tout d’abord un tout petit peu de théorie sur ce que l’on va faire. On partira de l’application que je développe actuellement, TwittLook, intégrant Twitter à OutLook 2010.
On a deux scénarios, « first connection » et « daily connection ».
First Connection
- L’application TwittLook possède deux clefs sur le principe de clefs privé/publique. Ce qui est cool, c’est que à part le fait que l’on devra garder la seconde « secrète », la seul chose que l’on fera avec, c’est les renseigner dans deux propriétés, LinqToTwitter s’occupe du reste (sans jeux de mots ^^).
- Ensuite notre application renverra l’utilisateur vers twitter directement afin qu’il valide l’accès de notre application à son compte.

- Si l’utilisateur accepte, il recevra un code PIN que l’on utilisera pour générer deux nouvelles clefs. Ces deux clefs seront stockées et nous permettrons les fois suivante de directement se connecter au compte de l’utilisateur.

Daily Connection
- Idem que le point 1 de First Connection
- On renseigne les tokens obtenue au point 3 de First Connection
- Enjoy
Et c’est tout… Sur ces deux scénarios sont résumé tout ce qu’il est nécessaire de connaitre pour developper une appli twitter ! Plus leger que les 120pages de RFC OAuth n’est-ce pas ?
Maintenant, comment fait-on concrètement ?
Premièrement, si ce n’est déjà fait, rendez-vous sur la partie développeur de twitter et enregistrez votre application. C’est gratuit et sans validation, le seul requirement c’est un compte valide. Cette authentification nous permettra d’obtenir les deux clefs. La première peut être public, la seconde doit rester privée (et donc protégée).

Les deux clefs dans le notepad, direction l’onglet settings dans la section « Application Type ». Nous allons là définir les droits d’accès de notre application. Libre à vous de prendre l’option qui vous convient selon vos besoins, la suite ne changera pas, mais de base les applications sont en Read-Only.
Les keys obtenue, nous allons créer un objet de type PinAuthorizer. Dans cet objet nous allons définir notre ConsumerKey, ConsumerSecret, Action à utiliser lorsque l’on se rend sur la page d’autorisation et une fonction à exécuter pour récupérer le code PIN. Dans mon cas j’ai stocké les key dans un fichier settings. Voici donc le code pour initialiser notre objet :
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = keys.Default.ConsumerKey,
ConsumerSecret = keys.Default.ConsumerSecret
},
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine("Enter the PIN Number : \n");
return Console.ReadLine();
}
};
Ensuite, si les tokens n’existent pas, cela signifie que l’application n’est pas authentifiée, nous appelons la méthode Authorize(). Ceci exécutera la méthode GoToTwitterAuthorization suivi de GetPin(). Ensuite dans notre code il nous suffit de récupéré dans la propriété Credentials les deux tokens (OAuthToken et AccessToken) que nous stockerons. Ainsi les fois suivante l’appel d’Authorize ne sera plus nécessaire. Et c’est tout ^^
Voici le code complet :
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = keys.Default.ConsumerKey,
ConsumerSecret = keys.Default.ConsumerSecret
},
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine("Enter the PIN Number : \n");
return Console.ReadLine();
}
};
if (keys.Default.OAuthToken.Trim() != "" && keys.Default.AccessToken.Trim() != "")
{
auth.Credentials = new InMemoryCredentials
{
ConsumerKey = keys.Default.ConsumerKey,
ConsumerSecret = keys.Default.ConsumerSecret,
OAuthToken = keys.Default.OAuthToken,
AccessToken = keys.Default.AccessToken
};
}
else
{
auth.Authorize();
keys.Default.OAuthToken = auth.Credentials.OAuthToken;
keys.Default.AccessToken = auth.Credentials.AccessToken;
keys.Default.Save();
}
if (auth.IsAuthorized)
{
using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/"))
{
//Log
twitterCtx.Log = Console.Out;
var message = twitterCtx.NewDirectMessage("TchoyTchoy", "Direct Message Test - " + DateTime.Now);
}
}
L’API OAuth va beaucoup plus loin, notamment sur des scénarios très complexe, mais la plupart du temps, ceci devrais suffire ^^
Un petit wallpaper Visual Studio 2010 ?
septembre 25th, 2011 § Laisser un commentaire
Voici un petit wallpaper que j’ai réalisé pour le site http://vs2010wallpapers.com/ entre deux prises de têtes avec de l’interop Visio 2010.
Events fantôme et interop office
septembre 24th, 2011 § Laisser un commentaire
Je développe actuellement une application ou j’ai besoin d’intégrer l’éditeur de dessin Visio et, entre autre, m’abonner a certains événements. Seul soucis, l’évènement survient de manière aléatoire. Après quelques heures de recherche et l’écriture d’un wrapper de COM event qui a donné le même résultat, j’ai trouvé ceci sur un forum concernant un problème d’event dans outlook.
The reason is: “GC collect the .NET object, whichc wrapps COM object from Outlook )”. The solution is hold reference to this .NET object.
La solution, simplement garder une référence sur l’objet. Dans mon cas, ma page Visio dans un attribut privé
Enregistrer des fichiers dans SQL Server 2008 en C#
septembre 23rd, 2011 § Laisser un commentaire
Voici comment stocker sur un SQL server tous type de fichier. En fait, il suffit d’avoir un champ de type varbinary dans lequel on enregistrera un byte[] de notre fichier. Donc pas de choses spéciales sur ADO, juste deux méthodes. La première retournant un byte[] d’un fichier et la seconde écrivant dans un fichier un byte[]
public void writeFile(byte[] data, String fileName)
{
using (BinaryWriter binWriter = new BinaryWriter(File.Open(fileName, FileMode.Create)))
{
binWriter.Write(data);
}
}
public byte[] ReadFile(string sPath)
{
byte[] data = null;
FileInfo fInfo = new FileInfo(sPath);
long numBytes = fInfo.Length;
FileStream fStream = new FileStream(sPath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fStream);
data = br.ReadBytes((int)numBytes);
return data;
}
Pour le principe, voici deux méthodes, upload et download qui les utilisent.
public void Download(string outputPath, string filename, string ConnectionString)
{
// Connection
SqlConnection CN = new SqlConnection(ConnectionString);
// Creation de la requête
string qry = "Select * from Files WHERE filename=@filename";
SqlCommand SqlCom = new SqlCommand(qry, CN);
SqlCom.Parameters.Add(new SqlParameter("@filename", (object)filename));
SqlDataAdapter ADAP = new SqlDataAdapter(SqlCom.CommandText, CN);
// Récupération des données
DataSet DS = new DataSet();
ADAP.Fill(DS, "Files");
// Lecture des données
foreach (DataRow dr in DS.Tables["Files"].Rows)
{
// enregistrement du fichier
writeFile((byte[])dr["data"], outputPath + dr["filename"]);
}
CN.Close();
}
public void UploadNewFile(string sourcePath, string description, string ConnectionString)
{
// Lecture du fichier
byte[] data = ReadFile(sourcePath);
// Nouvelle connection
SqlConnection CN = new SqlConnection(ConnectionString);
// Création de la requête
string qry = "insert into Files(filename, data, description) values (@filename, @data, @description)";
SqlCommand SqlCom = new SqlCommand(qry, CN);
SqlCom.Parameters.Add(new SqlParameter("@filename", (object)sourcePath.Split('\\').Last()));
SqlCom.Parameters.Add(new SqlParameter("@data", (object)data));
SqlCom.Parameters.Add(new SqlParameter("@description", (object)description));
// Ouverture, execution, fermeture
CN.Open();
SqlCom.ExecuteNonQuery();
CN.Close();
}
Par extension, cette méthode devrait fonctionner sur n’importe quel SGBD capable d’enregistrer des données de type binaire. Si certains ont testé sous oracle, mysql, db2 et cie, je serais interessé de savoir ce qu’il en est ^^



